mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
split ast handling into a separate module directory.
This commit is contained in:
parent
65a3c48110
commit
4265b0177b
18
src/ast/mod.rs
Normal file
18
src/ast/mod.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
//! The definitions of the ucg AST and Tokens.
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
pub mod tree;
|
@ -11,8 +11,6 @@
|
|||||||
// 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;
|
||||||
@ -108,10 +106,10 @@ impl Borrow<str> for Token {
|
|||||||
|
|
||||||
/// Helper macro for making a Positioned Value.
|
/// 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)
|
||||||
};
|
};
|
||||||
($v:expr, $l:expr, $c:expr) => {
|
($v: expr, $l: expr, $c: expr) => {
|
||||||
Positioned::new($v, $l, $c)
|
Positioned::new($v, $l, $c)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -119,31 +117,31 @@ macro_rules! value_node {
|
|||||||
/// Helper macro for making a Token.
|
/// 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) => {
|
||||||
Token::new("", TokenType::END, $l, $c)
|
Token::new("", TokenType::END, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( WS => $l:expr, $c:expr ) => {
|
(WS => $l: expr, $c: expr) => {
|
||||||
Token::new("", TokenType::WS, $l, $c)
|
Token::new("", TokenType::WS, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( CMT => $e:expr, $l:expr, $c:expr ) => {
|
(CMT => $e: expr, $l: expr, $c: expr) => {
|
||||||
Token::new($e, TokenType::COMMENT, $l, $c)
|
Token::new($e, TokenType::COMMENT, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( QUOT => $e:expr, $l:expr, $c:expr ) => {
|
(QUOT => $e: expr, $l: expr, $c: expr) => {
|
||||||
Token::new($e, TokenType::QUOTED, $l, $c)
|
Token::new($e, TokenType::QUOTED, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( PUNCT => $e:expr, $l:expr, $c:expr ) => {
|
(PUNCT => $e: expr, $l: expr, $c: expr) => {
|
||||||
Token::new($e, TokenType::PUNCT, $l, $c)
|
Token::new($e, TokenType::PUNCT, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( DIGIT => $e:expr, $l:expr, $c:expr ) => {
|
(DIGIT => $e: expr, $l: expr, $c: expr) => {
|
||||||
Token::new($e, TokenType::DIGIT, $l, $c)
|
Token::new($e, TokenType::DIGIT, $l, $c)
|
||||||
};
|
};
|
||||||
|
|
||||||
( $e:expr, $l:expr, $c:expr ) => {
|
($e: expr, $l: expr, $c: expr) => {
|
||||||
Token::new($e, TokenType::BAREWORD, $l, $c)
|
Token::new($e, TokenType::BAREWORD, $l, $c)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -151,15 +149,15 @@ macro_rules! make_tok {
|
|||||||
/// Helper macro for making expressions.
|
/// Helper macro for making expressions.
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! make_expr {
|
macro_rules! make_expr {
|
||||||
( $e:expr ) => {
|
($e: expr) => {
|
||||||
make_expr!($e, 1, 1)
|
make_expr!($e, 1, 1)
|
||||||
};
|
};
|
||||||
|
|
||||||
( $e:expr, $l:expr, $c:expr ) => {
|
($e: expr, $l: expr, $c: expr) => {
|
||||||
Expression::Simple(Value::Symbol(Positioned::new($e.to_string(), $l, $c)))
|
Expression::Simple(Value::Symbol(Positioned::new($e.to_string(), $l, $c)))
|
||||||
};
|
};
|
||||||
|
|
||||||
( $e:expr => int, $l:expr, $c:expr ) => {
|
($e: expr => int, $l: expr, $c: expr) => {
|
||||||
Expression::Simple(Value::Int(Positioned::new($e, $l, $c)))
|
Expression::Simple(Value::Int(Positioned::new($e, $l, $c)))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -543,10 +541,13 @@ impl MacroDef {
|
|||||||
while stack.len() > 0 {
|
while stack.len() > 0 {
|
||||||
match stack.pop().unwrap() {
|
match stack.pop().unwrap() {
|
||||||
&Expression::Binary(ref bexpr) => {
|
&Expression::Binary(ref bexpr) => {
|
||||||
let mut syms_set = self.validate_value_symbols(&mut stack, &bexpr.left);
|
stack.push(&bexpr.left);
|
||||||
bad_symbols.extend(syms_set.drain());
|
|
||||||
stack.push(&bexpr.right);
|
stack.push(&bexpr.right);
|
||||||
}
|
}
|
||||||
|
&Expression::Compare(ref cexpr) => {
|
||||||
|
stack.push(&cexpr.left);
|
||||||
|
stack.push(&cexpr.right);
|
||||||
|
}
|
||||||
&Expression::Grouped(ref expr) => {
|
&Expression::Grouped(ref expr) => {
|
||||||
stack.push(expr);
|
stack.push(expr);
|
||||||
}
|
}
|
||||||
@ -602,6 +603,10 @@ pub enum BinaryExprType {
|
|||||||
Sub,
|
Sub,
|
||||||
Mul,
|
Mul,
|
||||||
Div,
|
Div,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum CompareType {
|
||||||
Equal,
|
Equal,
|
||||||
GT,
|
GT,
|
||||||
LT,
|
LT,
|
||||||
@ -610,11 +615,19 @@ pub enum BinaryExprType {
|
|||||||
LTEqual,
|
LTEqual,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct ComparisonDef {
|
||||||
|
pub kind: CompareType,
|
||||||
|
pub left: Box<Expression>,
|
||||||
|
pub right: Box<Expression>,
|
||||||
|
pub pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
/// 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,
|
||||||
pub left: Value,
|
pub left: Box<Expression>,
|
||||||
pub right: Box<Expression>,
|
pub right: Box<Expression>,
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -665,6 +678,7 @@ pub enum Expression {
|
|||||||
|
|
||||||
// Binary expressions
|
// Binary expressions
|
||||||
Binary(BinaryOpDef),
|
Binary(BinaryOpDef),
|
||||||
|
Compare(ComparisonDef),
|
||||||
|
|
||||||
// Complex Expressions
|
// Complex Expressions
|
||||||
Copy(CopyDef),
|
Copy(CopyDef),
|
||||||
@ -682,6 +696,7 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
&Expression::Simple(ref v) => v.pos(),
|
&Expression::Simple(ref v) => v.pos(),
|
||||||
&Expression::Binary(ref def) => &def.pos,
|
&Expression::Binary(ref def) => &def.pos,
|
||||||
|
&Expression::Compare(ref def) => &def.pos,
|
||||||
&Expression::Copy(ref def) => &def.pos,
|
&Expression::Copy(ref def) => &def.pos,
|
||||||
&Expression::Grouped(ref expr) => expr.pos(),
|
&Expression::Grouped(ref expr) => expr.pos(),
|
||||||
&Expression::Format(ref def) => &def.pos,
|
&Expression::Format(ref def) => &def.pos,
|
||||||
@ -733,7 +748,11 @@ mod ast_test {
|
|||||||
make_tok!("f1", 1, 1),
|
make_tok!("f1", 1, 1),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Symbol(value_node!("foo".to_string(), 1, 1)),
|
left: Box::new(Expression::Simple(Value::Symbol(value_node!(
|
||||||
|
"foo".to_string(),
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -753,7 +772,11 @@ mod ast_test {
|
|||||||
make_tok!("f1", 1, 1),
|
make_tok!("f1", 1, 1),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Symbol(value_node!("bar".to_string(), 1, 1)),
|
left: Box::new(Expression::Simple(Value::Symbol(value_node!(
|
||||||
|
"bar".to_string(),
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -775,8 +798,10 @@ mod ast_test {
|
|||||||
make_tok!("f1", 1, 1),
|
make_tok!("f1", 1, 1),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Selector(make_selector!(make_expr!("foo", 1, 1) => [
|
left: Box::new(Expression::Simple(Value::Selector(
|
||||||
make_tok!("quux", 1, 1) ] => 1, 1)),
|
make_selector!(make_expr!("foo", 1, 1) => [
|
||||||
|
make_tok!("quux", 1, 1) ] => 1, 1),
|
||||||
|
))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -796,8 +821,10 @@ mod ast_test {
|
|||||||
make_tok!("f1", 1, 1),
|
make_tok!("f1", 1, 1),
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Selector(make_selector!(make_expr!("bar", 1, 1) => [
|
left: Box::new(Expression::Simple(Value::Selector(
|
||||||
make_tok!("quux", 1, 1) ] => 1, 1)),
|
make_selector!(make_expr!("bar", 1, 1) => [
|
||||||
|
make_tok!("quux", 1, 1) ] => 1, 1),
|
||||||
|
))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
454
src/build.rs
454
src/build.rs
@ -26,7 +26,7 @@ use std::rc::Rc;
|
|||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
|
|
||||||
use tokenizer::Span;
|
use tokenizer::Span;
|
||||||
use ast::*;
|
use ast::tree::*;
|
||||||
use format;
|
use format;
|
||||||
use parse::parse;
|
use parse::parse;
|
||||||
use error;
|
use error;
|
||||||
@ -295,18 +295,20 @@ pub struct Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! eval_binary_expr {
|
macro_rules! eval_binary_expr {
|
||||||
($case:pat, $pos:ident, $rside:ident, $result:expr, $msg:expr) => {
|
($case: pat, $pos: ident, $rside: ident, $result: expr, $msg: expr) => {
|
||||||
match $rside.as_ref() {
|
match $rside.as_ref() {
|
||||||
$case => {
|
$case => {
|
||||||
return Ok(Rc::new($result));
|
return Ok(Rc::new($result));
|
||||||
},
|
}
|
||||||
val => {
|
val => {
|
||||||
return Err(Box::new(
|
return Err(Box::new(error::Error::new(
|
||||||
error::Error::new(
|
format!("Expected {} but got {}", $msg, val),
|
||||||
format!("Expected {} but got {}", $msg, val), error::ErrorType::TypeFail, $pos.clone())));
|
error::ErrorType::TypeFail,
|
||||||
|
$pos.clone(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
@ -390,19 +392,28 @@ impl Builder {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a string of ucg syntax.
|
pub fn eval_string(&mut self, input: &str) -> Result<Rc<Val>, Box<Error>> {
|
||||||
pub fn build_file_string(&mut self, input: String) -> BuildResult {
|
match parse(Span::new(input)) {
|
||||||
match parse(Span::new(&input)) {
|
|
||||||
Ok(stmts) => {
|
Ok(stmts) => {
|
||||||
|
let mut out: Option<Rc<Val>> = None;
|
||||||
for stmt in stmts.iter() {
|
for stmt in stmts.iter() {
|
||||||
try!(self.build_stmt(stmt));
|
out = Some(try!(self.build_stmt(stmt)));
|
||||||
|
}
|
||||||
|
match out {
|
||||||
|
None => return Ok(Rc::new(Val::Empty)),
|
||||||
|
Some(val) => Ok(val),
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Err(err) => Err(Box::new(err)),
|
Err(err) => Err(Box::new(err)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a string of ucg syntax.
|
||||||
|
pub fn build_file_string(&mut self, input: String) -> BuildResult {
|
||||||
|
self.last = Some(try!(self.eval_string(&input)));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a ucg file at the named path.
|
/// 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));
|
||||||
@ -412,11 +423,11 @@ impl Builder {
|
|||||||
self.build_file_string(s)
|
self.build_file_string(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_import(&mut self, def: &ImportDef) -> BuildResult {
|
fn build_import(&mut self, def: &ImportDef) -> Result<Rc<Val>, Box<Error>> {
|
||||||
|
let sym = &def.name;
|
||||||
|
let positioned_sym = sym.into();
|
||||||
if !self.files.contains(&def.path.fragment) {
|
if !self.files.contains(&def.path.fragment) {
|
||||||
// Only parse the file once on import.
|
// Only parse the file once on import.
|
||||||
let sym = &def.name;
|
|
||||||
let positioned_sym = sym.into();
|
|
||||||
if self.assets.get(&positioned_sym).is_none() {
|
if self.assets.get(&positioned_sym).is_none() {
|
||||||
let mut b = Self::new();
|
let mut b = Self::new();
|
||||||
try!(b.build_file(&def.path.fragment));
|
try!(b.build_file(&def.path.fragment));
|
||||||
@ -424,15 +435,27 @@ impl Builder {
|
|||||||
let result = Rc::new(Val::Tuple(fields));
|
let result = Rc::new(Val::Tuple(fields));
|
||||||
self.assets.entry(positioned_sym).or_insert(result.clone());
|
self.assets.entry(positioned_sym).or_insert(result.clone());
|
||||||
self.files.insert(def.path.fragment.clone());
|
self.files.insert(def.path.fragment.clone());
|
||||||
self.last = Some(result);
|
return Ok(result);
|
||||||
|
} else {
|
||||||
|
return Ok(self.assets.get(&positioned_sym).unwrap().clone());
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return match self.assets.get(&positioned_sym) {
|
||||||
|
None => {
|
||||||
|
// some kind of error here I think.
|
||||||
|
Err(Box::new(error::Error::new(
|
||||||
|
"Unknown Error processing import",
|
||||||
|
error::ErrorType::Unsupported,
|
||||||
|
def.name.pos.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
Some(val) => Ok(val.clone()),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_let(&mut self, def: &LetDef) -> BuildResult {
|
fn build_let(&mut self, def: &LetDef) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let val = try!(self.eval_expr(&def.value));
|
let val = try!(self.eval_expr(&def.value));
|
||||||
self.last = Some(val.clone());
|
|
||||||
let name = &def.name;
|
let name = &def.name;
|
||||||
match self.out.entry(name.into()) {
|
match self.out.entry(name.into()) {
|
||||||
Entry::Occupied(e) => {
|
Entry::Occupied(e) => {
|
||||||
@ -448,25 +471,18 @@ impl Builder {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
e.insert(val);
|
e.insert(val.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_stmt(&mut self, stmt: &Statement) -> BuildResult {
|
fn build_stmt(&mut self, stmt: &Statement) -> Result<Rc<Val>, Box<Error>> {
|
||||||
match stmt {
|
match stmt {
|
||||||
&Statement::Let(ref def) => {
|
&Statement::Let(ref def) => self.build_let(def),
|
||||||
try!(self.build_let(def));
|
&Statement::Import(ref def) => self.build_import(def),
|
||||||
}
|
&Statement::Expression(ref expr) => self.eval_expr(expr),
|
||||||
&Statement::Import(ref def) => {
|
}
|
||||||
try!(self.build_import(def));
|
|
||||||
}
|
|
||||||
&Statement::Expression(ref expr) => {
|
|
||||||
self.last = Some(try!(self.eval_expr(expr)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_sym(&self, sym: &Positioned<String>) -> Option<Rc<Val>> {
|
fn lookup_sym(&self, sym: &Positioned<String>) -> Option<Rc<Val>> {
|
||||||
@ -859,21 +875,27 @@ impl Builder {
|
|||||||
|
|
||||||
fn eval_binary(&self, def: &BinaryOpDef) -> Result<Rc<Val>, Box<Error>> {
|
fn eval_binary(&self, def: &BinaryOpDef) -> Result<Rc<Val>, Box<Error>> {
|
||||||
let kind = &def.kind;
|
let kind = &def.kind;
|
||||||
let v = &def.left;
|
let left = try!(self.eval_expr(&def.left));
|
||||||
let expr = &def.right;
|
let right = try!(self.eval_expr(&def.right));
|
||||||
let right = try!(self.eval_expr(expr));
|
|
||||||
let left = try!(self.value_to_val(v));
|
|
||||||
match kind {
|
match kind {
|
||||||
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
|
&BinaryExprType::Add => self.add_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
|
&BinaryExprType::Sub => self.subtract_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
|
&BinaryExprType::Mul => self.multiply_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Div => self.divide_vals(&def.pos, left, right),
|
&BinaryExprType::Div => self.divide_vals(&def.pos, left, right),
|
||||||
&BinaryExprType::Equal => self.do_deep_equal(&def.pos, left, right),
|
}
|
||||||
&BinaryExprType::GT => self.do_gt(&def.pos, left, right),
|
}
|
||||||
&BinaryExprType::LT => self.do_lt(&def.pos, left, right),
|
|
||||||
&BinaryExprType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
fn eval_compare(&self, def: &ComparisonDef) -> Result<Rc<Val>, Box<Error>> {
|
||||||
&BinaryExprType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
let kind = &def.kind;
|
||||||
&BinaryExprType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
|
let left = try!(self.eval_expr(&def.left));
|
||||||
|
let right = try!(self.eval_expr(&def.right));
|
||||||
|
match kind {
|
||||||
|
&CompareType::Equal => self.do_deep_equal(&def.pos, left, right),
|
||||||
|
&CompareType::GT => self.do_gt(&def.pos, left, right),
|
||||||
|
&CompareType::LT => self.do_lt(&def.pos, left, right),
|
||||||
|
&CompareType::GTEqual => self.do_gtequal(&def.pos, left, right),
|
||||||
|
&CompareType::LTEqual => self.do_ltequal(&def.pos, left, right),
|
||||||
|
&CompareType::NotEqual => self.do_not_deep_equal(&def.pos, left, right),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1020,7 +1042,7 @@ impl Builder {
|
|||||||
return self.eval_expr(val_expr);
|
return self.eval_expr(val_expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Otherwise return the default
|
// Otherwise return the default.
|
||||||
return self.eval_expr(def_expr);
|
return self.eval_expr(def_expr);
|
||||||
} else {
|
} else {
|
||||||
return Err(Box::new(error::Error::new(
|
return Err(Box::new(error::Error::new(
|
||||||
@ -1071,11 +1093,11 @@ impl Builder {
|
|||||||
// 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 need a rewrite step to handle operator precendence order.
|
||||||
// Take a reference instead?
|
|
||||||
match expr {
|
match expr {
|
||||||
&Expression::Simple(ref val) => self.value_to_val(val),
|
&Expression::Simple(ref val) => self.value_to_val(val),
|
||||||
&Expression::Binary(ref def) => self.eval_binary(def),
|
&Expression::Binary(ref def) => self.eval_binary(def),
|
||||||
|
&Expression::Compare(ref def) => self.eval_compare(def),
|
||||||
&Expression::Copy(ref def) => self.eval_copy(def),
|
&Expression::Copy(ref def) => self.eval_copy(def),
|
||||||
&Expression::Grouped(ref expr) => self.eval_expr(expr),
|
&Expression::Grouped(ref expr) => self.eval_expr(expr),
|
||||||
&Expression::Format(ref def) => self.eval_format(def),
|
&Expression::Format(ref def) => self.eval_format(def),
|
||||||
@ -1087,6 +1109,95 @@ impl Builder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod compile_test {
|
||||||
|
use super::{Builder, Val};
|
||||||
|
|
||||||
|
fn assert_build<S: Into<String>>(input: S, assert: &str) {
|
||||||
|
let mut b = Builder::new();
|
||||||
|
b.build_file_string(input.into()).unwrap();
|
||||||
|
let result = b.eval_string(assert).unwrap();
|
||||||
|
if let &Val::Boolean(ok) = result.as_ref() {
|
||||||
|
assert!(ok, format!("'{}' is not true", assert));
|
||||||
|
} else {
|
||||||
|
assert!(
|
||||||
|
false,
|
||||||
|
format!("'{}' does not evaluate to a boolean: {:?}", assert, result)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_comparisons() {
|
||||||
|
let input = "
|
||||||
|
let one = 1;
|
||||||
|
let two = 2;
|
||||||
|
let foo = \"foo\";
|
||||||
|
let bar = \"bar\";
|
||||||
|
let tpl1 = {
|
||||||
|
foo = \"bar\",
|
||||||
|
one = 1
|
||||||
|
};
|
||||||
|
let tpl2 = tpl1{};
|
||||||
|
let tpl3 = {
|
||||||
|
bar = \"foo\",
|
||||||
|
two = 1
|
||||||
|
};
|
||||||
|
let list = [1, 2, 3];
|
||||||
|
let list2 = list;
|
||||||
|
let list3 = [1, 2];
|
||||||
|
";
|
||||||
|
assert_build(input, "one == one;");
|
||||||
|
assert_build(input, "one >= one;");
|
||||||
|
assert_build(input, "two > one;");
|
||||||
|
assert_build(input, "two >= two;");
|
||||||
|
assert_build(input, "tpl1 == tpl2;");
|
||||||
|
assert_build(input, "tpl1 != tpl3;");
|
||||||
|
assert_build(input, "list == list2;");
|
||||||
|
assert_build(input, "list != list3;");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deep_comparison() {
|
||||||
|
let input = "
|
||||||
|
let tpl1 = {
|
||||||
|
foo = \"bar\",
|
||||||
|
lst = [1, 2, 3],
|
||||||
|
inner = {
|
||||||
|
fld = \"value\"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let copy = tpl1;
|
||||||
|
let extra = tpl1{one = 1};
|
||||||
|
let less = {
|
||||||
|
foo = \"bar\"
|
||||||
|
};
|
||||||
|
";
|
||||||
|
|
||||||
|
assert_build(input, "tpl1.inner == copy.inner;");
|
||||||
|
assert_build(input, "tpl1.inner.fld == copy.inner.fld;");
|
||||||
|
assert_build(input, "tpl1.lst == copy.lst;");
|
||||||
|
assert_build(input, "tpl1.foo == copy.foo;");
|
||||||
|
assert_build(input, "tpl1 == copy;");
|
||||||
|
assert_build(input, "tpl1 != extra;");
|
||||||
|
assert_build(input, "tpl1 != less;");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_expression_comparisons() {
|
||||||
|
assert_build("", "2 == 1+1;");
|
||||||
|
assert_build("", "(1+1) == 2;");
|
||||||
|
assert_build("", "(1+1) == (1+1);");
|
||||||
|
assert_build("", "(\"foo\" + \"bar\") == \"foobar\";");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_binary_operator_precedence() {
|
||||||
|
assert_build("let result = 2 * 2 + 1;", "result == 6;");
|
||||||
|
assert_build("let result = (2 * 2) + 1;", "result == 5;");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::{Builder, CallDef, MacroDef, SelectDef, Val};
|
use super::{Builder, CallDef, MacroDef, SelectDef, Val};
|
||||||
@ -1107,7 +1218,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Div,
|
kind: BinaryExprType::Div,
|
||||||
left: Value::Int(value_node!(2, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1116,7 +1227,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Div,
|
kind: BinaryExprType::Div,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1136,7 +1247,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Div,
|
kind: BinaryExprType::Div,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1155,7 +1266,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Mul,
|
kind: BinaryExprType::Mul,
|
||||||
left: Value::Int(value_node!(2, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1164,7 +1275,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Mul,
|
kind: BinaryExprType::Mul,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1184,7 +1295,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Mul,
|
kind: BinaryExprType::Mul,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(20, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(20, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1203,7 +1314,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Sub,
|
kind: BinaryExprType::Sub,
|
||||||
left: Value::Int(value_node!(2, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1212,7 +1323,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Sub,
|
kind: BinaryExprType::Sub,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1232,7 +1343,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Sub,
|
kind: BinaryExprType::Sub,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1251,7 +1362,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Int(value_node!(1, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(1, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1260,7 +1371,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Float(value_node!(1.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Float(value_node!(1.0, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1269,7 +1380,11 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::String(value_node!("foo".to_string(), 1, 1)),
|
left: Box::new(Expression::Simple(Value::String(value_node!(
|
||||||
|
"foo".to_string(),
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
)))),
|
||||||
right: Box::new(Expression::Simple(Value::String(value_node!(
|
right: Box::new(Expression::Simple(Value::String(value_node!(
|
||||||
"bar".to_string(),
|
"bar".to_string(),
|
||||||
1,
|
1,
|
||||||
@ -1282,7 +1397,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::List(ListDef {
|
left: Box::new(Expression::Simple(Value::List(ListDef {
|
||||||
elems: vec![
|
elems: vec![
|
||||||
Expression::Simple(Value::String(value_node!(
|
Expression::Simple(Value::String(value_node!(
|
||||||
"foo".to_string(),
|
"foo".to_string(),
|
||||||
@ -1291,7 +1406,7 @@ mod test {
|
|||||||
))),
|
))),
|
||||||
],
|
],
|
||||||
pos: Position::new(1, 1),
|
pos: Position::new(1, 1),
|
||||||
}),
|
}))),
|
||||||
right: Box::new(Expression::Simple(Value::List(ListDef {
|
right: Box::new(Expression::Simple(Value::List(ListDef {
|
||||||
elems: vec![
|
elems: vec![
|
||||||
Expression::Simple(Value::String(value_node!(
|
Expression::Simple(Value::String(value_node!(
|
||||||
@ -1323,7 +1438,7 @@ mod test {
|
|||||||
(
|
(
|
||||||
Expression::Binary(BinaryOpDef {
|
Expression::Binary(BinaryOpDef {
|
||||||
kind: BinaryExprType::Add,
|
kind: BinaryExprType::Add,
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
left: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
||||||
pos: Position::new(1, 0),
|
pos: Position::new(1, 0),
|
||||||
}),
|
}),
|
||||||
@ -1334,223 +1449,6 @@ mod test {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_eval_equal_exprs() {
|
|
||||||
let b = Builder::new();
|
|
||||||
test_expr_to_val(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Int(value_node!(2, 1, 1)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Int(value_node!(2, 1, 1)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(true),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Float(value_node!(2.0, 1, 1)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Float(value_node!(2.0, 1, 1)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(true),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::String(value_node!("foo".to_string(), 1, 1)),
|
|
||||||
right: Box::new(Expression::Simple(Value::String(value_node!(
|
|
||||||
"foo".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(true),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(true),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blush".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(false),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bosh", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(false),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Expression::Binary(BinaryOpDef {
|
|
||||||
kind: BinaryExprType::Equal,
|
|
||||||
left: Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)),
|
|
||||||
right: Box::new(Expression::Simple(Value::Tuple(value_node!(
|
|
||||||
vec![
|
|
||||||
(
|
|
||||||
make_tok!("bash", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("bar", 1, 1),
|
|
||||||
Expression::Simple(Value::Int(value_node!(1, 1, 1))),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
make_tok!("foo", 1, 1),
|
|
||||||
Expression::Simple(Value::String(value_node!(
|
|
||||||
"blah".to_string(),
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
))),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
1,
|
|
||||||
1
|
|
||||||
)))),
|
|
||||||
pos: Position::new(1, 0),
|
|
||||||
}),
|
|
||||||
Val::Boolean(false),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
b,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_eval_simple_expr() {
|
fn test_eval_simple_expr() {
|
||||||
test_expr_to_val(
|
test_expr_to_val(
|
||||||
|
@ -17,7 +17,7 @@ use std::rc::Rc;
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::io::Result;
|
use std::io::Result;
|
||||||
|
|
||||||
use ast;
|
use ast::tree::*;
|
||||||
use build::Val;
|
use build::Val;
|
||||||
use convert::traits::Converter;
|
use convert::traits::Converter;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ impl EnvConverter {
|
|||||||
|
|
||||||
fn convert_tuple(
|
fn convert_tuple(
|
||||||
&self,
|
&self,
|
||||||
flds: &Vec<(ast::Positioned<String>, Rc<Val>)>,
|
flds: &Vec<(Positioned<String>, Rc<Val>)>,
|
||||||
w: &mut Write,
|
w: &mut Write,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for &(ref name, ref val) in flds.iter() {
|
for &(ref name, ref val) in flds.iter() {
|
||||||
|
@ -36,7 +36,7 @@ impl JsonConverter {
|
|||||||
|
|
||||||
fn convert_tuple(
|
fn convert_tuple(
|
||||||
&self,
|
&self,
|
||||||
items: &Vec<(ast::Positioned<String>, Rc<Val>)>,
|
items: &Vec<(ast::tree::Positioned<String>, Rc<Val>)>,
|
||||||
) -> Result<serde_json::Value> {
|
) -> Result<serde_json::Value> {
|
||||||
let mut mp = serde_json::Map::new();
|
let mut mp = serde_json::Map::new();
|
||||||
for &(ref k, ref v) in items.iter() {
|
for &(ref k, ref v) in items.iter() {
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use ast::*;
|
use ast::tree::*;
|
||||||
|
|
||||||
use nom;
|
use nom;
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
use std::clone::Clone;
|
use std::clone::Clone;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
use ast::*;
|
use ast::tree::*;
|
||||||
use error;
|
use error;
|
||||||
|
|
||||||
/// Implements the logic for format strings in UCG format expressions.
|
/// Implements the logic for format strings in UCG format expressions.
|
||||||
|
31
src/lib.rs
31
src/lib.rs
@ -243,11 +243,13 @@
|
|||||||
//!
|
//!
|
||||||
//! The `>`, `<`, `>=`, and `>=` operators are only supported on numeric types.
|
//! The `>`, `<`, `>=`, and `>=` operators are only supported on numeric types.
|
||||||
//!
|
//!
|
||||||
//! ``ucg
|
//! ```ucg
|
||||||
//! 1 > 2; // result is false
|
//! 1 > 2; // result is false
|
||||||
//! 2 < 3; // result is true
|
//! 2 < 3; // result is true
|
||||||
//! 10 > "9"; // This is a compile error.
|
//! 10 > "9"; // This is a compile error.
|
||||||
|
//! (1+2) == 3
|
||||||
//! ```
|
//! ```
|
||||||
|
//! The comparison operators expect either a simple value or a grouped expression as their left operand.
|
||||||
//!
|
//!
|
||||||
//! The equality operators `==` and `!=` are supported for all types and will perform deep equal comparisons on complex
|
//! The equality operators `==` and `!=` are supported for all types and will perform deep equal comparisons on complex
|
||||||
//! types.
|
//! types.
|
||||||
@ -266,25 +268,18 @@
|
|||||||
//! Note that tuple fields are ordered so a tuple will only be equal if the fields are both in the same order and
|
//! Note that tuple fields are ordered so a tuple will only be equal if the fields are both in the same order and
|
||||||
//! have the same values in them.
|
//! have the same values in them.
|
||||||
//!
|
//!
|
||||||
//! ##### Boolean
|
//! ##### Operator Precedence
|
||||||
//!
|
//!
|
||||||
//! ucg supports the following operators, `+`, `-`, `*`, `/`, `==`, `!=`, `>`, `<`, `>=`, `<=`, `&&`, `||` Each one is type safe and
|
//! ucg operators evaluate the right side first. If you want to enforce a different
|
||||||
//! infers the types from the values they operate on. The operators expect both the left and right operands to be of the same
|
//! order of operations you will need to use parentheses to group them. This is
|
||||||
//! type. All of the operators except `&&` and `||` are valid on integers and floats. The + operator can additionally concatenate
|
//! most evident when mixing numeric and comparison operators.
|
||||||
//! strings or arrays. The `&&` and `||` operators are only valid on booleans.
|
|
||||||
//!
|
//!
|
||||||
//! ```ucg
|
//! ```ucg
|
||||||
//! 1 + 1; // result is 2
|
//! 1+1 == 2; // this will be a type error. The + expects an integer but it has a boolean expression
|
||||||
//! "foo " + "bar" // result is "foo bar"
|
//! // on the right.
|
||||||
//! [1,2] + [3,4]; // result is [1,2,3,4]
|
//! (1+1) == 2; // this succeeds because the parentheses force evaluation of the addition first.
|
||||||
//! 1 == 1; // result is true.
|
|
||||||
//! 1 > 1; // result is false
|
|
||||||
//! 1 >= 1; // result is true;
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The Equality comparison can be done on any type and will perform a deep equal comparison.
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! #### Copy expressions
|
//! #### Copy expressions
|
||||||
//!
|
//!
|
||||||
//! ucg Tuples support a form of reuse with copy on write semantics. You can copy a tuple and selectively overwrite fields or add new
|
//! ucg Tuples support a form of reuse with copy on write semantics. You can copy a tuple and selectively overwrite fields or add new
|
||||||
@ -421,9 +416,9 @@ pub mod error;
|
|||||||
|
|
||||||
mod format;
|
mod format;
|
||||||
|
|
||||||
pub use ast::Value;
|
pub use ast::tree::Value;
|
||||||
pub use ast::Expression;
|
pub use ast::tree::Expression;
|
||||||
pub use ast::Statement;
|
pub use ast::tree::Statement;
|
||||||
|
|
||||||
pub use parse::parse;
|
pub use parse::parse;
|
||||||
pub use build::Builder;
|
pub use build::Builder;
|
||||||
|
@ -21,7 +21,7 @@ use nom;
|
|||||||
use nom::InputLength;
|
use nom::InputLength;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
use ast::*;
|
use ast::tree::*;
|
||||||
use tokenizer::*;
|
use tokenizer::*;
|
||||||
use error;
|
use error;
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ use nom_locate::LocatedSpan;
|
|||||||
use nom;
|
use nom;
|
||||||
use nom::{alpha, digit, is_alphanumeric, multispace};
|
use nom::{alpha, digit, is_alphanumeric, multispace};
|
||||||
use nom::{InputIter, InputLength, Slice};
|
use nom::{InputIter, InputLength, Slice};
|
||||||
use ast::*;
|
use ast::tree::*;
|
||||||
use error;
|
use error;
|
||||||
use std;
|
use std;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user