mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
The great documentation roundup.
Add docstrings for all kinds of types.
This commit is contained in:
parent
e3e8e68f19
commit
30c9bc64b2
70
src/ast.rs
70
src/ast.rs
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The definitions of the ucg AST and Tokens.
|
||||||
use std;
|
use std;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
@ -22,6 +24,7 @@ use std::cmp::PartialEq;
|
|||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
/// Encodes a parsing error with position information and a helpful description.
|
||||||
#[derive(Debug,PartialEq)]
|
#[derive(Debug,PartialEq)]
|
||||||
pub struct ParseError {
|
pub struct ParseError {
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
@ -61,6 +64,10 @@ macro_rules! enum_type_equality {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a line and a column position in UCG code.
|
||||||
|
///
|
||||||
|
/// It is used for generating error messages mostly. Most all
|
||||||
|
/// parts of the UCG AST have a positioned associated with them.
|
||||||
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
@ -68,6 +75,7 @@ pub struct Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
|
/// Construct a new Position.
|
||||||
pub fn new(line: usize, column: usize) -> Self {
|
pub fn new(line: usize, column: usize) -> Self {
|
||||||
Position {
|
Position {
|
||||||
line: line,
|
line: line,
|
||||||
@ -76,6 +84,7 @@ impl Position {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Defines the types of tokens in UCG syntax.
|
||||||
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
||||||
pub enum TokenType {
|
pub enum TokenType {
|
||||||
END,
|
END,
|
||||||
@ -88,6 +97,10 @@ pub enum TokenType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(jwall): We should probably implement copy for this.
|
// FIXME(jwall): We should probably implement copy for this.
|
||||||
|
|
||||||
|
/// Defines a Token representing a building block of UCG syntax.
|
||||||
|
///
|
||||||
|
/// Token's are passed to the parser stage to be parsed into an AST.
|
||||||
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
#[derive(Debug,PartialEq,Eq,Clone,PartialOrd,Ord,Hash)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub typ: TokenType,
|
pub typ: TokenType,
|
||||||
@ -96,10 +109,12 @@ pub struct Token {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Token {
|
impl Token {
|
||||||
|
/// Constructs a new Token with a type and line and column information.
|
||||||
pub fn new<S: Into<String>>(f: S, typ: TokenType, line: usize, col: usize) -> Self {
|
pub fn new<S: Into<String>>(f: S, typ: TokenType, line: usize, col: usize) -> Self {
|
||||||
Self::new_with_pos(f, typ, Position::new(line, col))
|
Self::new_with_pos(f, typ, Position::new(line, col))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constructs a new Token with a type and a Position.
|
||||||
pub fn new_with_pos<S: Into<String>>(f: S, typ: TokenType, pos: Position) -> Self {
|
pub fn new_with_pos<S: Into<String>>(f: S, typ: TokenType, pos: Position) -> Self {
|
||||||
Token {
|
Token {
|
||||||
typ: typ,
|
typ: typ,
|
||||||
@ -115,6 +130,7 @@ impl Borrow<str> for Token {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro for making a Positioned Value.
|
||||||
macro_rules! value_node {
|
macro_rules! value_node {
|
||||||
($v:expr, $p:expr) => {
|
($v:expr, $p:expr) => {
|
||||||
Positioned::new_with_pos($v, $p)
|
Positioned::new_with_pos($v, $p)
|
||||||
@ -124,6 +140,7 @@ macro_rules! value_node {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro for making a Token.
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! make_tok {
|
macro_rules! make_tok {
|
||||||
( EOF => $l:expr, $c:expr ) => {
|
( EOF => $l:expr, $c:expr ) => {
|
||||||
@ -155,6 +172,7 @@ macro_rules! make_tok {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper macro for making expressions.
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! make_expr {
|
macro_rules! make_expr {
|
||||||
( $e:expr ) => {
|
( $e:expr ) => {
|
||||||
@ -248,7 +266,7 @@ macro_rules! make_selector {
|
|||||||
col += $item.len() + 1;
|
col += $item.len() + 1;
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Shut up the lint about unused code;
|
// Shut up the linter about unused code;
|
||||||
assert!(col != 0);
|
assert!(col != 0);
|
||||||
|
|
||||||
make_selector!($h, list, $l, $c)
|
make_selector!($h, list, $l, $c)
|
||||||
@ -256,7 +274,7 @@ macro_rules! make_selector {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selector is an Expression with a series of symbols specifying the key
|
/// An Expression with a series of symbols specifying the key
|
||||||
/// with which to descend into the result of the expression.
|
/// with which to descend into the result of the expression.
|
||||||
///
|
///
|
||||||
/// The expression must evaluate to either a tuple or an array. The token must
|
/// The expression must evaluate to either a tuple or an array. The token must
|
||||||
@ -279,13 +297,18 @@ pub struct SelectorList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorList {
|
impl SelectorList {
|
||||||
|
/// Returns a stringified version of a SelectorList.
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
"TODO".to_string()
|
"TODO".to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An ordered list of Name = Value pairs.
|
||||||
|
///
|
||||||
|
/// This is usually used as the body of a tuple in the UCG AST.
|
||||||
pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
|
pub type FieldList = Vec<(Token, Expression)>; // Token is expected to be a symbol
|
||||||
|
|
||||||
|
/// Encodes a selector expression in the UCG AST.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct SelectorDef {
|
pub struct SelectorDef {
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
@ -293,6 +316,7 @@ pub struct SelectorDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SelectorDef {
|
impl SelectorDef {
|
||||||
|
/// Constructs a new SelectorDef.
|
||||||
pub fn new(sel: SelectorList, line: usize, col: usize) -> Self {
|
pub fn new(sel: SelectorList, line: usize, col: usize) -> Self {
|
||||||
SelectorDef {
|
SelectorDef {
|
||||||
pos: Position::new(line, col),
|
pos: Position::new(line, col),
|
||||||
@ -301,7 +325,7 @@ impl SelectorDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Value represents a Value in the UCG parsed AST.
|
/// Represents a Value in the UCG parsed AST.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
// Constant Values
|
// Constant Values
|
||||||
@ -316,6 +340,7 @@ pub enum Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
/// Returns the type name of the Value it is called on as a string.
|
||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Value::Int(_) => "Integer".to_string(),
|
&Value::Int(_) => "Integer".to_string(),
|
||||||
@ -344,6 +369,7 @@ impl Value {
|
|||||||
return format!("{}", v.len());
|
return format!("{}", v.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a stringified version of the Value.
|
||||||
pub fn to_string(&self) -> String {
|
pub fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Value::Int(ref i) => format!("{}", i.val),
|
&Value::Int(ref i) => format!("{}", i.val),
|
||||||
@ -356,6 +382,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the position for a Value.
|
||||||
pub fn pos(&self) -> &Position {
|
pub fn pos(&self) -> &Position {
|
||||||
match self {
|
match self {
|
||||||
&Value::Int(ref i) => &i.pos,
|
&Value::Int(ref i) => &i.pos,
|
||||||
@ -368,6 +395,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if called on a Value that is the same type as itself.
|
||||||
pub fn type_equal(&self, target: &Self) -> bool {
|
pub fn type_equal(&self, target: &Self) -> bool {
|
||||||
enum_type_equality!(self, target, &Value::Int(_),
|
enum_type_equality!(self, target, &Value::Int(_),
|
||||||
&Value::Float(_),
|
&Value::Float(_),
|
||||||
@ -379,7 +407,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// CallDef represents a call to a Macro that is expected to already have been
|
/// Represents an expansion of a Macro that is expected to already have been
|
||||||
/// defined.
|
/// defined.
|
||||||
#[derive(PartialEq,Debug,Clone)]
|
#[derive(PartialEq,Debug,Clone)]
|
||||||
pub struct CallDef {
|
pub struct CallDef {
|
||||||
@ -388,8 +416,7 @@ pub struct CallDef {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SelectDef selects a value from a tuple with a default if the value doesn't
|
/// Encodes a select expression in the UCG AST.
|
||||||
/// exist.
|
|
||||||
#[derive(PartialEq,Debug,Clone)]
|
#[derive(PartialEq,Debug,Clone)]
|
||||||
pub struct SelectDef {
|
pub struct SelectDef {
|
||||||
pub val: Box<Expression>,
|
pub val: Box<Expression>,
|
||||||
@ -399,6 +426,8 @@ pub struct SelectDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jwall): This should have a way of rendering with position information.
|
// TODO(jwall): This should have a way of rendering with position information.
|
||||||
|
|
||||||
|
/// Adds position information to any type `T`.
|
||||||
#[derive(Debug,Clone)]
|
#[derive(Debug,Clone)]
|
||||||
pub struct Positioned<T> {
|
pub struct Positioned<T> {
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
@ -406,10 +435,12 @@ pub struct Positioned<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Positioned<T> {
|
impl<T> Positioned<T> {
|
||||||
|
/// Constructs a new Positioned<T> with a value, line, and column information.
|
||||||
pub fn new(v: T, l: usize, c: usize) -> Self {
|
pub fn new(v: T, l: usize, c: usize) -> Self {
|
||||||
Self::new_with_pos(v, Position::new(l, c))
|
Self::new_with_pos(v, Position::new(l, c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a new Positioned<T> with a value and a Position.
|
||||||
pub fn new_with_pos(v: T, pos: Position) -> Self {
|
pub fn new_with_pos(v: T, pos: Position) -> Self {
|
||||||
Positioned { pos: pos, val: v }
|
Positioned { pos: pos, val: v }
|
||||||
}
|
}
|
||||||
@ -459,9 +490,10 @@ impl<'a> From<&'a Positioned<String>> for Positioned<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MacroDef is a pure function that always returns a Tuple.
|
/// Encodes a macro expression in the UCG AST..
|
||||||
///
|
///
|
||||||
/// MacroDef's are not closures. They can not reference
|
/// A macro is a pure function over a tuple.
|
||||||
|
/// MacroDefs are not closures. They can not reference
|
||||||
/// any values except what is defined in their arguments.
|
/// any values except what is defined in their arguments.
|
||||||
#[derive(PartialEq,Debug,Clone)]
|
#[derive(PartialEq,Debug,Clone)]
|
||||||
pub struct MacroDef {
|
pub struct MacroDef {
|
||||||
@ -504,6 +536,8 @@ impl MacroDef {
|
|||||||
return bad_symbols;
|
return bad_symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Performs typechecking of a ucg macro's arguments to ensure
|
||||||
|
/// that they are valid for the expressions in the macro.
|
||||||
pub fn validate_symbols(&self) -> Result<(), HashSet<String>> {
|
pub fn validate_symbols(&self) -> Result<(), HashSet<String>> {
|
||||||
let mut bad_symbols = HashSet::new();
|
let mut bad_symbols = HashSet::new();
|
||||||
for &(_, ref expr) in self.fields.iter() {
|
for &(_, ref expr) in self.fields.iter() {
|
||||||
@ -561,6 +595,8 @@ impl MacroDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specifies the types of binary operations supported in
|
||||||
|
/// UCG expression.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub enum BinaryExprType {
|
pub enum BinaryExprType {
|
||||||
Add,
|
Add,
|
||||||
@ -569,7 +605,7 @@ pub enum BinaryExprType {
|
|||||||
Div,
|
Div,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BinaryOpDef represents an expression with a left and a right side.
|
/// Represents an expression with a left and a right side.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct BinaryOpDef {
|
pub struct BinaryOpDef {
|
||||||
pub kind: BinaryExprType,
|
pub kind: BinaryExprType,
|
||||||
@ -578,6 +614,7 @@ pub struct BinaryOpDef {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes a tuple Copy expression in the UCG AST.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct CopyDef {
|
pub struct CopyDef {
|
||||||
pub selector: SelectorDef,
|
pub selector: SelectorDef,
|
||||||
@ -585,6 +622,7 @@ pub struct CopyDef {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes a format expression in the UCG AST.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct FormatDef {
|
pub struct FormatDef {
|
||||||
pub template: String,
|
pub template: String,
|
||||||
@ -592,33 +630,33 @@ pub struct FormatDef {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes a list expression in the UCG AST.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub struct ListDef {
|
pub struct ListDef {
|
||||||
pub elems: Vec<Expression>,
|
pub elems: Vec<Expression>,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Expression encodes an expression. Expressions compute a value from operands.
|
/// Encodes a ucg expression. Expressions compute a value from.
|
||||||
#[derive(Debug,PartialEq,Clone)]
|
#[derive(Debug,PartialEq,Clone)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
// Base Expression
|
// Base Expression
|
||||||
Simple(Value),
|
Simple(Value),
|
||||||
|
|
||||||
|
// Binary expressions
|
||||||
Binary(BinaryOpDef),
|
Binary(BinaryOpDef),
|
||||||
|
|
||||||
// Complex Expressions
|
// Complex Expressions
|
||||||
Copy(CopyDef),
|
Copy(CopyDef),
|
||||||
Grouped(Box<Expression>),
|
Grouped(Box<Expression>),
|
||||||
|
|
||||||
Format(FormatDef),
|
Format(FormatDef),
|
||||||
|
|
||||||
Call(CallDef),
|
Call(CallDef),
|
||||||
|
|
||||||
Macro(MacroDef),
|
Macro(MacroDef),
|
||||||
Select(SelectDef),
|
Select(SelectDef),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
|
/// Returns the position of the Expression.
|
||||||
pub fn pos(&self) -> &Position {
|
pub fn pos(&self) -> &Position {
|
||||||
match self {
|
match self {
|
||||||
&Expression::Simple(ref v) => v.pos(),
|
&Expression::Simple(ref v) => v.pos(),
|
||||||
@ -633,19 +671,21 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes a let statement in the UCG AST.
|
||||||
#[derive(Debug,PartialEq)]
|
#[derive(Debug,PartialEq)]
|
||||||
pub struct LetDef {
|
pub struct LetDef {
|
||||||
pub name: Token,
|
pub name: Token,
|
||||||
pub value: Expression,
|
pub value: Expression,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Encodes an import statement in the UCG AST.
|
||||||
#[derive(Debug,PartialEq)]
|
#[derive(Debug,PartialEq)]
|
||||||
pub struct ImportDef {
|
pub struct ImportDef {
|
||||||
pub path: Token,
|
pub path: Token,
|
||||||
pub name: Token,
|
pub name: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Statement encodes a parsed Statement in the UCG AST.
|
/// Encodes a parsed statement in the UCG AST.
|
||||||
#[derive(Debug,PartialEq)]
|
#[derive(Debug,PartialEq)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
// simple expression
|
// simple expression
|
||||||
@ -654,7 +694,7 @@ pub enum Statement {
|
|||||||
// Named bindings
|
// Named bindings
|
||||||
Let(LetDef),
|
Let(LetDef),
|
||||||
|
|
||||||
// Include a file.
|
// Import a file.
|
||||||
Import(ImportDef),
|
Import(ImportDef),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
27
src/build.rs
27
src/build.rs
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The build stage of the ucg compiler.
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
@ -29,6 +31,7 @@ use parse::parse;
|
|||||||
use error;
|
use error;
|
||||||
|
|
||||||
impl MacroDef {
|
impl MacroDef {
|
||||||
|
/// Expands a ucg Macro using the given arguments into a new Tuple.
|
||||||
pub fn eval(&self,
|
pub fn eval(&self,
|
||||||
mut args: Vec<Rc<Val>>)
|
mut args: Vec<Rc<Val>>)
|
||||||
-> Result<Vec<(Positioned<String>, Rc<Val>)>, Box<Error>> {
|
-> Result<Vec<(Positioned<String>, Rc<Val>)>, Box<Error>> {
|
||||||
@ -59,10 +62,10 @@ impl MacroDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// BuildResult is the result of a build.
|
/// The result of a build.
|
||||||
type BuildResult = Result<(), Box<Error>>;
|
type BuildResult = Result<(), Box<Error>>;
|
||||||
|
|
||||||
/// Val is the Intermediate representation of a compiled UCG AST.
|
/// The Intermediate representation of a compiled UCG AST.
|
||||||
#[derive(PartialEq,Debug,Clone)]
|
#[derive(PartialEq,Debug,Clone)]
|
||||||
pub enum Val {
|
pub enum Val {
|
||||||
Int(i64),
|
Int(i64),
|
||||||
@ -74,6 +77,7 @@ pub enum Val {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Val {
|
impl Val {
|
||||||
|
/// Returns the Type of a Val as a string.
|
||||||
pub fn type_name(&self) -> String {
|
pub fn type_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
&Val::Int(_) => "Integer".to_string(),
|
&Val::Int(_) => "Integer".to_string(),
|
||||||
@ -85,6 +89,7 @@ impl Val {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if called with a Val of the same type as itself.
|
||||||
pub fn type_equal(&self, target: &Self) -> bool {
|
pub fn type_equal(&self, target: &Self) -> bool {
|
||||||
enum_type_equality!(self, target, &Val::Int(_),
|
enum_type_equality!(self, target, &Val::Int(_),
|
||||||
&Val::Float(_),
|
&Val::Float(_),
|
||||||
@ -94,6 +99,7 @@ impl Val {
|
|||||||
&Val::Macro(_))
|
&Val::Macro(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the fields if this Val is a tuple. None otherwise.
|
||||||
pub fn get_fields(&self) -> Option<&Vec<(Positioned<String>, Rc<Val>)>> {
|
pub fn get_fields(&self) -> Option<&Vec<(Positioned<String>, Rc<Val>)>> {
|
||||||
if let &Val::Tuple(ref fs) = self {
|
if let &Val::Tuple(ref fs) = self {
|
||||||
Some(fs)
|
Some(fs)
|
||||||
@ -174,10 +180,10 @@ impl From<Val> for String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ValueMap defines a set of values in a parsed file.
|
/// Defines a set of values in a parsed file.
|
||||||
type ValueMap = HashMap<Positioned<String>, Rc<Val>>;
|
type ValueMap = HashMap<Positioned<String>, Rc<Val>>;
|
||||||
|
|
||||||
/// Builder parses one or more statements into a out Tuple.
|
/// Handles building ucg code.
|
||||||
pub struct Builder {
|
pub struct Builder {
|
||||||
/// assets are other parsed files from import statements. They
|
/// assets are other parsed files from import statements. They
|
||||||
/// are keyed by the normalized import path. This acts as a cache
|
/// are keyed by the normalized import path. This acts as a cache
|
||||||
@ -208,7 +214,6 @@ macro_rules! eval_binary_expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
// TODO(jwall): Maintain order for tuples.
|
|
||||||
fn tuple_to_val(&self, fields: &Vec<(Token, Expression)>) -> Result<Rc<Val>, Box<Error>> {
|
fn tuple_to_val(&self, fields: &Vec<(Token, Expression)>) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let mut new_fields = Vec::<(Positioned<String>, Rc<Val>)>::new();
|
let mut new_fields = Vec::<(Positioned<String>, Rc<Val>)>::new();
|
||||||
for &(ref name, ref expr) in fields.iter() {
|
for &(ref name, ref expr) in fields.iter() {
|
||||||
@ -245,6 +250,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a new Builder.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Builder {
|
Builder {
|
||||||
assets: HashMap::new(),
|
assets: HashMap::new(),
|
||||||
@ -254,6 +260,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a new Builder with a provided scope.
|
||||||
pub fn new_with_scope(scope: ValueMap) -> Self {
|
pub fn new_with_scope(scope: ValueMap) -> Self {
|
||||||
Builder {
|
Builder {
|
||||||
assets: HashMap::new(),
|
assets: HashMap::new(),
|
||||||
@ -263,6 +270,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a Val by name from previously built UCG.
|
||||||
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
pub fn get_out_by_name(&self, name: &str) -> Option<Rc<Val>> {
|
||||||
let key = Positioned {
|
let key = Positioned {
|
||||||
pos: Position::new(0, 0),
|
pos: Position::new(0, 0),
|
||||||
@ -271,6 +279,7 @@ impl Builder {
|
|||||||
self.lookup_sym(&key)
|
self.lookup_sym(&key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a list of parsed UCG Statements.
|
||||||
pub fn build(&mut self, ast: &Vec<Statement>) -> BuildResult {
|
pub fn build(&mut self, ast: &Vec<Statement>) -> BuildResult {
|
||||||
for stmt in ast.iter() {
|
for stmt in ast.iter() {
|
||||||
try!(self.build_stmt(stmt));
|
try!(self.build_stmt(stmt));
|
||||||
@ -278,7 +287,8 @@ impl Builder {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_file_string(&mut self, _name: &str, input: String) -> BuildResult {
|
/// Builds a string of ucg syntax.
|
||||||
|
pub fn build_file_string(&mut self, input: String) -> BuildResult {
|
||||||
match parse(Span::new(&input)) {
|
match parse(Span::new(&input)) {
|
||||||
Ok(stmts) => {
|
Ok(stmts) => {
|
||||||
for stmt in stmts.iter() {
|
for stmt in stmts.iter() {
|
||||||
@ -290,12 +300,13 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a ucg file at the named path.
|
||||||
pub fn build_file(&mut self, name: &str) -> BuildResult {
|
pub fn build_file(&mut self, name: &str) -> BuildResult {
|
||||||
let mut f = try!(File::open(name));
|
let mut f = try!(File::open(name));
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
// TODO(jwall): It would be nice to be able to do this while streaming
|
// TODO(jwall): It would be nice to be able to do this while streaming
|
||||||
try!(f.read_to_string(&mut s));
|
try!(f.read_to_string(&mut s));
|
||||||
self.build_file_string(name, s)
|
self.build_file_string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_import(&mut self, def: &ImportDef) -> BuildResult {
|
fn build_import(&mut self, def: &ImportDef) -> BuildResult {
|
||||||
@ -769,7 +780,7 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eval_expr evals a single Expression in the context of a running Builder.
|
// Evals a single Expression in the context of a running Builder.
|
||||||
// It does not mutate the builders collected state at all.
|
// It does not mutate the builders collected state at all.
|
||||||
pub fn eval_expr(&self, expr: &Expression) -> Result<Rc<Val>, Box<Error>> {
|
pub fn eval_expr(&self, expr: &Expression) -> Result<Rc<Val>, Box<Error>> {
|
||||||
// TODO(jwall): We probably don't want to consume these expressions.
|
// TODO(jwall): We probably don't want to consume these expressions.
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Flags contains code for converting a UCG Val into the command line flag output target.
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
@ -19,6 +20,7 @@ use std::io::Result;
|
|||||||
use build::Val;
|
use build::Val;
|
||||||
use convert::traits::Converter;
|
use convert::traits::Converter;
|
||||||
|
|
||||||
|
/// FlagConverter implements the conversion logic for converting a Val into a set of command line flags.
|
||||||
pub struct FlagConverter {}
|
pub struct FlagConverter {}
|
||||||
|
|
||||||
impl FlagConverter {
|
impl FlagConverter {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
//! Flags contains code for converting a UCG Val into the json output target.
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
@ -18,6 +18,7 @@ use ast;
|
|||||||
use build::Val;
|
use build::Val;
|
||||||
use convert::traits::Converter;
|
use convert::traits::Converter;
|
||||||
|
|
||||||
|
/// JsonConverter implements the logic for converting a Val into the json output format.
|
||||||
pub struct JsonConverter {}
|
pub struct JsonConverter {}
|
||||||
|
|
||||||
impl JsonConverter {
|
impl JsonConverter {
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The conversion stage of the ucg compiler.
|
||||||
pub mod flags;
|
pub mod flags;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
@ -21,11 +23,16 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use build::Val;
|
use build::Val;
|
||||||
|
|
||||||
|
/// ConverterRunner knows how to run a given converter on a Val.
|
||||||
pub struct ConverterRunner {
|
pub struct ConverterRunner {
|
||||||
converter: Box<traits::Converter>,
|
converter: Box<traits::Converter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConverterRunner {
|
impl ConverterRunner {
|
||||||
|
/// new creates a new ConverterRunner with a converter for the provided output target.
|
||||||
|
///
|
||||||
|
/// * flags
|
||||||
|
/// * json
|
||||||
pub fn new(typ: &str) -> Result<Self, String> {
|
pub fn new(typ: &str) -> Result<Self, String> {
|
||||||
if typ == "flags" {
|
if typ == "flags" {
|
||||||
return Ok(ConverterRunner { converter: Box::new(flags::FlagConverter::new()) });
|
return Ok(ConverterRunner { converter: Box::new(flags::FlagConverter::new()) });
|
||||||
@ -36,6 +43,7 @@ impl ConverterRunner {
|
|||||||
return Err(format!("Unknown Target output type: {}", typ));
|
return Err(format!("Unknown Target output type: {}", typ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// convert runs the Converter on a Val and writes the output to the provided writer.
|
||||||
pub fn convert(&self, v: Rc<Val>, w: Box<Write>) -> io::Result<()> {
|
pub fn convert(&self, v: Rc<Val>, w: Box<Write>) -> io::Result<()> {
|
||||||
self.converter.convert(v, w)
|
self.converter.convert(v, w)
|
||||||
}
|
}
|
||||||
|
@ -12,12 +12,15 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The traits used by the ucg compiler for converting Val intermediate format into the output formats..
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
|
||||||
use build::Val;
|
use build::Val;
|
||||||
|
|
||||||
|
/// The trait that Converters from Val to different output formats for the
|
||||||
|
/// final conversion stage of the ucg compiler.
|
||||||
pub trait Converter {
|
pub trait Converter {
|
||||||
fn convert(&self, vs: Rc<Val>, w: Box<Write>) -> Result<()>;
|
fn convert(&self, vs: Rc<Val>, w: Box<Write>) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
17
src/error.rs
17
src/error.rs
@ -1,9 +1,25 @@
|
|||||||
|
// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Errors for use by the ucg compiler.
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ast::*;
|
use ast::*;
|
||||||
|
|
||||||
|
/// ErrorType defines the various types of errors that can result from compiling UCG into an
|
||||||
|
/// output format.
|
||||||
pub enum ErrorType {
|
pub enum ErrorType {
|
||||||
// Build Errors
|
// Build Errors
|
||||||
TypeFail,
|
TypeFail,
|
||||||
@ -35,6 +51,7 @@ impl fmt::Display for ErrorType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Error defines an Error type for parsing and building UCG code.
|
||||||
pub struct Error {
|
pub struct Error {
|
||||||
pub err_type: ErrorType,
|
pub err_type: ErrorType,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
|
@ -12,18 +12,21 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The format string logic for ucg format expressions.
|
||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use ast::*;
|
use ast::*;
|
||||||
use error;
|
use error;
|
||||||
|
|
||||||
|
/// Implements the logic for format strings in UCG format expressions.
|
||||||
pub struct Formatter<V: Into<String> + Clone> {
|
pub struct Formatter<V: Into<String> + Clone> {
|
||||||
tmpl: String,
|
tmpl: String,
|
||||||
args: Vec<V>,
|
args: Vec<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: Into<String> + Clone> Formatter<V> {
|
impl<V: Into<String> + Clone> Formatter<V> {
|
||||||
|
/// Constructs a Formatter with a template and args.
|
||||||
pub fn new<S: Into<String>>(tmpl: S, args: Vec<V>) -> Self {
|
pub fn new<S: Into<String>>(tmpl: S, args: Vec<V>) -> Self {
|
||||||
Formatter {
|
Formatter {
|
||||||
tmpl: tmpl.into(),
|
tmpl: tmpl.into(),
|
||||||
@ -31,6 +34,10 @@ impl<V: Into<String> + Clone> Formatter<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renders a formatter to a string or returns an error.
|
||||||
|
///
|
||||||
|
/// If the formatter has the wrong number of arguments for the number of replacements
|
||||||
|
/// it will return an error. Otherwise it will return the formatted string.
|
||||||
pub fn render(&self, pos: &Position) -> Result<String, Box<Error>> {
|
pub fn render(&self, pos: &Position) -> Result<String, Box<Error>> {
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let mut should_escape = false;
|
let mut should_escape = false;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The Parsing stage of the ucg compiler.
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
@ -591,6 +593,7 @@ named!(statement<TokenIter, Statement, ParseError>,
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Parses a LocatedSpan into a list of Statements or a ParseError.
|
||||||
pub fn parse(input: LocatedSpan<&str>) -> Result<Vec<Statement>, ParseError> {
|
pub fn parse(input: LocatedSpan<&str>) -> Result<Vec<Statement>, ParseError> {
|
||||||
match tokenize(input) {
|
match tokenize(input) {
|
||||||
Ok(tokenized) => {
|
Ok(tokenized) => {
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! The tokenization stage of the ucg compiler.
|
||||||
use nom_locate::LocatedSpan;
|
use nom_locate::LocatedSpan;
|
||||||
use nom;
|
use nom;
|
||||||
use nom::{alpha, is_alphanumeric, digit, multispace};
|
use nom::{alpha, is_alphanumeric, digit, multispace};
|
||||||
@ -286,6 +288,8 @@ named!(token( Span ) -> Token,
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO(jwall): This should return a ParseError instead.
|
// TODO(jwall): This should return a ParseError instead.
|
||||||
|
|
||||||
|
/// Consumes an input Span and returns either a Vec<Token> or a nom::ErrorKind.
|
||||||
pub fn tokenize(input: Span) -> Result<Vec<Token>, nom::ErrorKind> {
|
pub fn tokenize(input: Span) -> Result<Vec<Token>, nom::ErrorKind> {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
let mut i = input;
|
let mut i = input;
|
||||||
@ -326,6 +330,8 @@ pub fn token_clone(t: &Token) -> Result<Token, ParseError> {
|
|||||||
Ok(t.clone())
|
Ok(t.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// nom macro that matches a Token by type and uses an optional conversion handler
|
||||||
|
/// for the matched Token.
|
||||||
macro_rules! match_type {
|
macro_rules! match_type {
|
||||||
($i:expr, COMMENT => $h:expr) => {
|
($i:expr, COMMENT => $h:expr) => {
|
||||||
match_type!($i, TokenType::COMMENT, "Not a Comment", $h)
|
match_type!($i, TokenType::COMMENT, "Not a Comment", $h)
|
||||||
@ -396,6 +402,8 @@ macro_rules! match_type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// nom style macro that matches various Tokens by type and value and allows optional
|
||||||
|
/// conversion handlers for the matched Token.
|
||||||
macro_rules! match_token {
|
macro_rules! match_token {
|
||||||
($i:expr, PUNCT => $f:expr) => {
|
($i:expr, PUNCT => $f:expr) => {
|
||||||
match_token!($i, PUNCT => $f, token_clone)
|
match_token!($i, PUNCT => $f, token_clone)
|
||||||
@ -434,18 +442,21 @@ macro_rules! match_token {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// nom style macro that matches punctuation Tokens.
|
||||||
macro_rules! punct {
|
macro_rules! punct {
|
||||||
($i:expr, $c:expr) => {
|
($i:expr, $c:expr) => {
|
||||||
match_token!($i, PUNCT => $c)
|
match_token!($i, PUNCT => $c)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// nom style macro that matches any bareword Token.
|
||||||
macro_rules! word {
|
macro_rules! word {
|
||||||
($i:expr, $w:expr) => {
|
($i:expr, $w:expr) => {
|
||||||
match_token!($i, BAREWORD => $w)
|
match_token!($i, BAREWORD => $w)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// pos gets the current position from a TokenIter input without consuming it.
|
||||||
pub fn pos(i: TokenIter) -> nom::IResult<TokenIter, Position, ParseError> {
|
pub fn pos(i: TokenIter) -> nom::IResult<TokenIter, Position, ParseError> {
|
||||||
let tok = &i[0];
|
let tok = &i[0];
|
||||||
let line = tok.pos.line;
|
let line = tok.pos.line;
|
||||||
@ -457,6 +468,8 @@ pub fn pos(i: TokenIter) -> nom::IResult<TokenIter, Position, ParseError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TokenIter wraps a slice of Tokens and implements the various necessary
|
||||||
|
/// nom traits to use it as an input to nom parsers.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct TokenIter<'a> {
|
pub struct TokenIter<'a> {
|
||||||
pub source: &'a [Token],
|
pub source: &'a [Token],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user