Broken structure now gets through syntax evaluator.
This commit is contained in:
25
examples/basic/broken0001.ngr
Normal file
25
examples/basic/broken0001.ngr
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
struct Point {
|
||||||
|
x: u64;
|
||||||
|
y: u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getX(p: Point) -> u64
|
||||||
|
p.x;
|
||||||
|
|
||||||
|
function getY(p: Point) -> u64
|
||||||
|
p.y;
|
||||||
|
|
||||||
|
function newPoint(x, y) -> Point
|
||||||
|
Point {
|
||||||
|
x: x;
|
||||||
|
y: y;
|
||||||
|
};
|
||||||
|
|
||||||
|
function slope(p1, p2) -> u64
|
||||||
|
(getY(p2) - p1.y) / (getX(p2) - p1.x);
|
||||||
|
|
||||||
|
origin = newPoint(0, 0);
|
||||||
|
farther = newPoint(4, 4);
|
||||||
|
|
||||||
|
mySlope = slope(origin, farther);
|
||||||
|
print mySlope;
|
||||||
18
src/eval.rs
18
src/eval.rs
@@ -86,6 +86,14 @@ pub enum EvalError<IR> {
|
|||||||
usize,
|
usize,
|
||||||
usize,
|
usize,
|
||||||
),
|
),
|
||||||
|
#[error("Value has no fields {1} (attempt to get field {2} at {0:?})")]
|
||||||
|
NoFieldForValue(crate::syntax::Location, Value<IR>, ArcIntern<String>),
|
||||||
|
#[error("Bad field {2} for structure {1:?} at {0:?}")]
|
||||||
|
BadFieldForStructure(
|
||||||
|
crate::syntax::Location,
|
||||||
|
Option<ArcIntern<String>>,
|
||||||
|
ArcIntern<String>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<IR1: Clone, IR2: Clone> PartialEq<EvalError<IR1>> for EvalError<IR2> {
|
impl<IR1: Clone, IR2: Clone> PartialEq<EvalError<IR1>> for EvalError<IR2> {
|
||||||
@@ -149,6 +157,16 @@ impl<IR1: Clone, IR2: Clone> PartialEq<EvalError<IR1>> for EvalError<IR2> {
|
|||||||
EvalError::WrongArgCount(w, x, y, z) => a == w && b == x && c == y && d == z,
|
EvalError::WrongArgCount(w, x, y, z) => a == w && b == x && c == y && d == z,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
EvalError::NoFieldForValue(a, b, c) => match other {
|
||||||
|
EvalError::NoFieldForValue(x, y, z) => a == x && b == y && c == z,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
|
||||||
|
EvalError::BadFieldForStructure(a, b, c) => match other {
|
||||||
|
EvalError::BadFieldForStructure(x, y, z) => a == x && b == y && c == z,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ impl<IR: Clone> Value<IR> {
|
|||||||
right.clone(),
|
right.clone(),
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
Value::Closure(_, _, _, _) | Value::Void => {
|
Value::Closure(_, _, _, _) | Value::Structure(_, _) | Value::Void => {
|
||||||
Err(PrimOpError::BadTypeFor(operation.to_string(), left.clone()))
|
Err(PrimOpError::BadTypeFor(operation.to_string(), left.clone()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,8 @@ impl Display for PrimitiveType {
|
|||||||
pub enum ValuePrimitiveTypeError {
|
pub enum ValuePrimitiveTypeError {
|
||||||
#[error("Could not convert function value to primitive type (possible function name: {0:?}")]
|
#[error("Could not convert function value to primitive type (possible function name: {0:?}")]
|
||||||
CannotConvertFunction(Option<String>),
|
CannotConvertFunction(Option<String>),
|
||||||
|
#[error("Could not convert structure value to primitive type (possible function name: {0:?}")]
|
||||||
|
CannotConvertStructure(Option<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, IR> TryFrom<&'a Value<IR>> for PrimitiveType {
|
impl<'a, IR> TryFrom<&'a Value<IR>> for PrimitiveType {
|
||||||
@@ -67,6 +69,9 @@ impl<'a, IR> TryFrom<&'a Value<IR>> for PrimitiveType {
|
|||||||
Value::Closure(name, _, _, _) => Err(ValuePrimitiveTypeError::CannotConvertFunction(
|
Value::Closure(name, _, _, _) => Err(ValuePrimitiveTypeError::CannotConvertFunction(
|
||||||
name.as_ref().map(|x| (**x).clone()),
|
name.as_ref().map(|x| (**x).clone()),
|
||||||
)),
|
)),
|
||||||
|
Value::Structure(name, _) => Err(ValuePrimitiveTypeError::CannotConvertStructure(
|
||||||
|
name.as_ref().map(|x| (**x).clone()),
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::util::scoped_map::ScopedMap;
|
use crate::util::scoped_map::ScopedMap;
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// Values in the interpreter.
|
/// Values in the interpreter.
|
||||||
@@ -26,6 +27,10 @@ pub enum Value<IR> {
|
|||||||
Vec<ArcIntern<String>>,
|
Vec<ArcIntern<String>>,
|
||||||
IR,
|
IR,
|
||||||
),
|
),
|
||||||
|
Structure(
|
||||||
|
Option<ArcIntern<String>>,
|
||||||
|
HashMap<ArcIntern<String>, Value<IR>>,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<IR: Clone> Value<IR> {
|
impl<IR: Clone> Value<IR> {
|
||||||
@@ -50,6 +55,10 @@ impl<IR: Clone> Value<IR> {
|
|||||||
let new_env = env.clone().map_values(|x| x.strip());
|
let new_env = env.clone().map_values(|x| x.strip());
|
||||||
Value::Closure(name.clone(), new_env, args.clone(), ())
|
Value::Closure(name.clone(), new_env, args.clone(), ())
|
||||||
}
|
}
|
||||||
|
Value::Structure(name, fields) => Value::Structure(
|
||||||
|
name.clone(),
|
||||||
|
fields.iter().map(|(n, v)| (n.clone(), v.strip())).collect(),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,6 +77,16 @@ fn format_value<IR>(value: &Value<IR>, f: &mut fmt::Formatter<'_>) -> fmt::Resul
|
|||||||
Value::Number(x) => write!(f, "{}", x),
|
Value::Number(x) => write!(f, "{}", x),
|
||||||
Value::Closure(Some(name), _, _, _) => write!(f, "<function {}>", name),
|
Value::Closure(Some(name), _, _, _) => write!(f, "<function {}>", name),
|
||||||
Value::Closure(None, _, _, _) => write!(f, "<function>"),
|
Value::Closure(None, _, _, _) => write!(f, "<function>"),
|
||||||
|
Value::Structure(on, fields) => {
|
||||||
|
if let Some(n) = on {
|
||||||
|
write!(f, "{}", n.as_str())?;
|
||||||
|
}
|
||||||
|
write!(f, "{{")?;
|
||||||
|
for (n, v) in fields.iter() {
|
||||||
|
write!(f, " {}: {},", n, v)?;
|
||||||
|
}
|
||||||
|
write!(f, " }}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +151,20 @@ impl<IR1, IR2> PartialEq<Value<IR2>> for Value<IR1> {
|
|||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
Value::Closure(_, _, _, _) => false,
|
Value::Closure(_, _, _, _) => false,
|
||||||
|
Value::Structure(on1, fields1) => match other {
|
||||||
|
Value::Structure(on2, fields2) => {
|
||||||
|
on1 == on2 && {
|
||||||
|
let left = fields1.keys().all(|x| fields2.contains_key(x));
|
||||||
|
let right = fields2.keys().all(|x| fields1.contains_key(x));
|
||||||
|
|
||||||
|
left && right
|
||||||
|
&& fields1
|
||||||
|
.iter()
|
||||||
|
.all(|(k, v)| fields2.get(k).map(|v2| v == v2).unwrap_or(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,13 @@ pub struct Program {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum TopLevel {
|
pub enum TopLevel {
|
||||||
Statement(Statement),
|
Statement(Statement),
|
||||||
Function(Option<Name>, Vec<Name>, Expression),
|
Function(
|
||||||
|
Option<Name>,
|
||||||
|
Vec<(Name, Option<Type>)>,
|
||||||
|
Option<Type>,
|
||||||
|
Expression,
|
||||||
|
),
|
||||||
|
Structure(Location, Option<Name>, Vec<(Name, Type)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Name.
|
/// A Name.
|
||||||
@@ -126,7 +132,9 @@ impl PartialEq for Statement {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Value(Location, Value),
|
Value(Location, Value),
|
||||||
|
Constructor(Location, Name, Vec<(Name, Expression)>),
|
||||||
Reference(Location, String),
|
Reference(Location, String),
|
||||||
|
FieldRef(Location, Box<Expression>, Name),
|
||||||
Cast(Location, String, Box<Expression>),
|
Cast(Location, String, Box<Expression>),
|
||||||
Primitive(Location, String, Vec<Expression>),
|
Primitive(Location, String, Vec<Expression>),
|
||||||
Call(Location, Box<Expression>, Vec<Expression>),
|
Call(Location, Box<Expression>, Vec<Expression>),
|
||||||
@@ -140,10 +148,18 @@ impl PartialEq for Expression {
|
|||||||
Expression::Value(_, val2) => val1 == val2,
|
Expression::Value(_, val2) => val1 == val2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
Expression::Constructor(_, name1, fields1) => match other {
|
||||||
|
Expression::Constructor(_, name2, fields2) => name1 == name2 && fields1 == fields2,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
Expression::Reference(_, var1) => match other {
|
Expression::Reference(_, var1) => match other {
|
||||||
Expression::Reference(_, var2) => var1 == var2,
|
Expression::Reference(_, var2) => var1 == var2,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
Expression::FieldRef(_, exp1, field1) => match other {
|
||||||
|
Expression::FieldRef(_, exp2, field2) => exp1 == exp2 && field1 == field2,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
Expression::Cast(_, t1, e1) => match other {
|
Expression::Cast(_, t1, e1) => match other {
|
||||||
Expression::Cast(_, t2, e2) => t1 == t2 && e1 == e2,
|
Expression::Cast(_, t2, e2) => t1 == t2 && e1 == e2,
|
||||||
_ => false,
|
_ => false,
|
||||||
@@ -169,7 +185,9 @@ impl Expression {
|
|||||||
pub fn location(&self) -> &Location {
|
pub fn location(&self) -> &Location {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(loc, _) => loc,
|
Expression::Value(loc, _) => loc,
|
||||||
|
Expression::Constructor(loc, _, _) => loc,
|
||||||
Expression::Reference(loc, _) => loc,
|
Expression::Reference(loc, _) => loc,
|
||||||
|
Expression::FieldRef(loc, _, _) => loc,
|
||||||
Expression::Cast(loc, _, _) => loc,
|
Expression::Cast(loc, _, _) => loc,
|
||||||
Expression::Primitive(loc, _, _) => loc,
|
Expression::Primitive(loc, _, _) => loc,
|
||||||
Expression::Call(loc, _, _) => loc,
|
Expression::Call(loc, _, _) => loc,
|
||||||
@@ -190,3 +208,9 @@ pub enum Value {
|
|||||||
/// number at a later time.
|
/// number at a later time.
|
||||||
Number(Option<u8>, Option<ConstantType>, u64),
|
Number(Option<u8>, Option<ConstantType>, u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub enum Type {
|
||||||
|
Named(Name),
|
||||||
|
Struct(Option<Name>, Vec<(Option<Name>, Option<Type>)>),
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::eval::{EvalError, PrimitiveType, Value};
|
|||||||
use crate::syntax::{ConstantType, Expression, Name, Program, Statement, TopLevel};
|
use crate::syntax::{ConstantType, Expression, Name, Program, Statement, TopLevel};
|
||||||
use crate::util::scoped_map::ScopedMap;
|
use crate::util::scoped_map::ScopedMap;
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
@@ -23,11 +24,15 @@ impl Program {
|
|||||||
|
|
||||||
for stmt in self.items.iter() {
|
for stmt in self.items.iter() {
|
||||||
match stmt {
|
match stmt {
|
||||||
TopLevel::Function(name, arg_names, body) => {
|
TopLevel::Function(name, arg_names, _, body) => {
|
||||||
last_result = Value::Closure(
|
last_result = Value::Closure(
|
||||||
name.clone().map(Name::intern),
|
name.clone().map(Name::intern),
|
||||||
env.clone(),
|
env.clone(),
|
||||||
arg_names.iter().cloned().map(Name::intern).collect(),
|
arg_names
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|(x, _)| Name::intern(x))
|
||||||
|
.collect(),
|
||||||
body.clone(),
|
body.clone(),
|
||||||
);
|
);
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
@@ -36,6 +41,10 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TopLevel::Statement(stmt) => last_result = stmt.eval(&mut stdout, &mut env)?,
|
TopLevel::Statement(stmt) => last_result = stmt.eval(&mut stdout, &mut env)?,
|
||||||
|
|
||||||
|
TopLevel::Structure(_, _, _) => {
|
||||||
|
last_result = Value::Void;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,11 +107,43 @@ impl Expression {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
Expression::Constructor(_, on, fields) => {
|
||||||
|
let mut map = HashMap::with_capacity(fields.len());
|
||||||
|
|
||||||
|
for (k, v) in fields.iter() {
|
||||||
|
map.insert(k.clone().intern(), v.eval(stdout, env)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Value::Structure(Some(on.clone().intern()), map))
|
||||||
|
}
|
||||||
|
|
||||||
Expression::Reference(loc, n) => env
|
Expression::Reference(loc, n) => env
|
||||||
.get(&ArcIntern::new(n.clone()))
|
.get(&ArcIntern::new(n.clone()))
|
||||||
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.clone()))
|
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.clone()))
|
||||||
.cloned(),
|
.cloned(),
|
||||||
|
|
||||||
|
Expression::FieldRef(loc, expr, field) => {
|
||||||
|
let struck = expr.eval(stdout, env)?;
|
||||||
|
|
||||||
|
if let Value::Structure(on, mut fields) = struck {
|
||||||
|
if let Some(value) = fields.remove(&field.clone().intern()) {
|
||||||
|
Ok(value)
|
||||||
|
} else {
|
||||||
|
Err(EvalError::BadFieldForStructure(
|
||||||
|
loc.clone(),
|
||||||
|
on,
|
||||||
|
field.clone().intern(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(EvalError::NoFieldForValue(
|
||||||
|
loc.clone(),
|
||||||
|
struck,
|
||||||
|
field.clone().intern(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expression::Cast(_, target, expr) => {
|
Expression::Cast(_, target, expr) => {
|
||||||
let target_type = PrimitiveType::from_str(target)?;
|
let target_type = PrimitiveType::from_str(target)?;
|
||||||
let value = expr.eval(stdout, env)?;
|
let value = expr.eval(stdout, env)?;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
//! eventually want to leave lalrpop behind.)
|
//! eventually want to leave lalrpop behind.)
|
||||||
//!
|
//!
|
||||||
use crate::syntax::{Location, ParserError};
|
use crate::syntax::{Location, ParserError};
|
||||||
use crate::syntax::ast::{Program,TopLevel,Statement,Expression,Value,Name};
|
use crate::syntax::ast::{Program,TopLevel,Statement,Expression,Value,Name,Type};
|
||||||
use crate::syntax::tokens::{ConstantType, Token};
|
use crate::syntax::tokens::{ConstantType, Token};
|
||||||
use internment::ArcIntern;
|
use internment::ArcIntern;
|
||||||
|
|
||||||
@@ -29,16 +29,21 @@ extern {
|
|||||||
// here we redeclare all of the tokens.
|
// here we redeclare all of the tokens.
|
||||||
enum Token {
|
enum Token {
|
||||||
"=" => Token::Equals,
|
"=" => Token::Equals,
|
||||||
|
":" => Token::Colon,
|
||||||
";" => Token::Semi,
|
";" => Token::Semi,
|
||||||
"," => Token::Comma,
|
"," => Token::Comma,
|
||||||
|
"." => Token::Dot,
|
||||||
"(" => Token::LeftParen,
|
"(" => Token::LeftParen,
|
||||||
")" => Token::RightParen,
|
")" => Token::RightParen,
|
||||||
"<" => Token::LessThan,
|
"<" => Token::LessThan,
|
||||||
">" => Token::GreaterThan,
|
">" => Token::GreaterThan,
|
||||||
|
"_" => Token::Underscore,
|
||||||
"{" => Token::OpenBrace,
|
"{" => Token::OpenBrace,
|
||||||
"}" => Token::CloseBrace,
|
"}" => Token::CloseBrace,
|
||||||
|
"->" => Token::SingleArrow,
|
||||||
|
|
||||||
"function" => Token::Function,
|
"function" => Token::Function,
|
||||||
|
"struct" => Token::Struct,
|
||||||
"print" => Token::Print,
|
"print" => Token::Print,
|
||||||
|
|
||||||
"+" => Token::Operator('+'),
|
"+" => Token::Operator('+'),
|
||||||
@@ -53,6 +58,7 @@ extern {
|
|||||||
// which is why we put their types in angle brackets.
|
// which is why we put their types in angle brackets.
|
||||||
"<num>" => Token::Number((<Option<u8>>,<Option<ConstantType>>,<u64>)),
|
"<num>" => Token::Number((<Option<u8>>,<Option<ConstantType>>,<u64>)),
|
||||||
"<var>" => Token::Variable(<ArcIntern<String>>),
|
"<var>" => Token::Variable(<ArcIntern<String>>),
|
||||||
|
"<type>" => Token::TypeName(<ArcIntern<String>>),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,38 +80,18 @@ ProgramTopLevel: Vec<TopLevel> = {
|
|||||||
|
|
||||||
pub TopLevel: TopLevel = {
|
pub TopLevel: TopLevel = {
|
||||||
<f:Function> => f,
|
<f:Function> => f,
|
||||||
|
<s:Structure> => s,
|
||||||
<s:Statement> ";" => TopLevel::Statement(s),
|
<s:Statement> ";" => TopLevel::Statement(s),
|
||||||
}
|
}
|
||||||
|
|
||||||
Function: TopLevel = {
|
Function: TopLevel = {
|
||||||
"function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <exp:Expression> ";" =>
|
"function" <opt_name:Name?> "(" <args:Comma<Argument>> ")" <ret:("->" Type)?> <exp:Expression> ";" =>
|
||||||
TopLevel::Function(opt_name, args, exp),
|
TopLevel::Function(opt_name, args, ret.map(|x| x.1), exp),
|
||||||
// "function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <s:@L> "{" "}" <e:@L> =>
|
|
||||||
// TopLevel::Function(opt_name, args, Expression::Block(Location::new(file_idx, s..e), vec![])),
|
|
||||||
// "function" <opt_name:OptionalName> "(" <args:Arguments> OptionalComma ")" <s:@L> "{" <stmts:Statements> "}" <e:@L> =>
|
|
||||||
// TopLevel::Function(opt_name, args, Expression::Block(Location::new(file_idx, s..e), stmts)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalName: Option<Name> = {
|
Argument: (Name, Option<Type>) = {
|
||||||
<name_start: @L> <v:"<var>"> <name_end: @L> =>
|
<name_start: @L> <v:"<var>"> <name_end: @L> <t:(":" Type)?> =>
|
||||||
Some(Name::new(v, Location::new(file_idx, name_start..name_end))),
|
(Name::new(v, Location::new(file_idx, name_start..name_end)), t.map(|v| v.1)),
|
||||||
=> None,
|
|
||||||
}
|
|
||||||
|
|
||||||
Arguments: Vec<Name> = {
|
|
||||||
<mut args:Arguments> "," <arg:Argument> => {
|
|
||||||
args.push(arg);
|
|
||||||
args
|
|
||||||
},
|
|
||||||
|
|
||||||
<arg:Argument> => vec![arg],
|
|
||||||
|
|
||||||
=> Vec::new(),
|
|
||||||
}
|
|
||||||
|
|
||||||
Argument: Name = {
|
|
||||||
<name_start: @L> <v:"<var>"> <name_end: @L> =>
|
|
||||||
Name::new(v, Location::new(file_idx, name_start..name_end)),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionalComma: () = {
|
OptionalComma: () = {
|
||||||
@@ -113,6 +99,40 @@ OptionalComma: () = {
|
|||||||
"," => (),
|
"," => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Structure: TopLevel = {
|
||||||
|
<s:@L> "struct" <on: TypeName?> "{" <fields: Field*> "}" <e:@L> => {
|
||||||
|
TopLevel::Structure(Location::new(file_idx, s..e), on, fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Field: (Name, Type) = {
|
||||||
|
<s:@L> <name:"<var>"> <e:@L> ":" <field_type: Type> ";" =>
|
||||||
|
(Name::new(name, Location::new(file_idx, s..e)), field_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
Type: Type = {
|
||||||
|
<name:Name> => Type::Named(name),
|
||||||
|
<t:TypeName> => Type::Named(t),
|
||||||
|
"struct" <on: TypeName?> "{" <fields: TypeField*> "}" =>
|
||||||
|
Type::Struct(on, fields),
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeField: (Option<Name>, Option<Type>) = {
|
||||||
|
<name: Name> ":" <ty: Type> ";" => (Some(name), Some(ty)),
|
||||||
|
<name: Name> (":" "_")? ";" => (Some(name), None),
|
||||||
|
"_" ":" <ty: Type> ";" => (None, Some(ty)),
|
||||||
|
}
|
||||||
|
|
||||||
|
Name: Name = {
|
||||||
|
<name_start: @L> <v:"<var>"> <name_end: @L> =>
|
||||||
|
Name::new(v, Location::new(file_idx, name_start..name_end)),
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeName: Name = {
|
||||||
|
<name_start: @L> <v:"<type>"> <name_end: @L> =>
|
||||||
|
Name::new(v, Location::new(file_idx, name_start..name_end)),
|
||||||
|
}
|
||||||
|
|
||||||
Statements: Vec<Statement> = {
|
Statements: Vec<Statement> = {
|
||||||
// a statement is either a set of statements followed by another
|
// a statement is either a set of statements followed by another
|
||||||
// statement (note, here, that you can name the result of a sub-parse
|
// statement (note, here, that you can name the result of a sub-parse
|
||||||
@@ -175,9 +195,19 @@ Statement: Statement = {
|
|||||||
// parse something like "1 + 2 * 3", for example, versus "1 + 2 + 3" or
|
// parse something like "1 + 2 * 3", for example, versus "1 + 2 + 3" or
|
||||||
// "1 * 2 + 3", and hopefully that'll help.
|
// "1 * 2 + 3", and hopefully that'll help.
|
||||||
Expression: Expression = {
|
Expression: Expression = {
|
||||||
|
ConstructorExpression,
|
||||||
AdditiveExpression,
|
AdditiveExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConstructorExpression: Expression = {
|
||||||
|
<s:@L> <name:TypeName> "{" <fields:FieldSetter*> "}" <e:@L> =>
|
||||||
|
Expression::Constructor(Location::new(file_idx, s..e), name, fields),
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldSetter: (Name, Expression) = {
|
||||||
|
<name:Name> ":" <expr:Expression> ";" => (name, expr),
|
||||||
|
}
|
||||||
|
|
||||||
// we group addition and subtraction under the heading "additive"
|
// we group addition and subtraction under the heading "additive"
|
||||||
AdditiveExpression: Expression = {
|
AdditiveExpression: Expression = {
|
||||||
<ls: @L> <e1:AdditiveExpression> <l: @L> "+" <e2:MultiplicativeExpression> <le: @L> =>
|
<ls: @L> <e1:AdditiveExpression> <l: @L> "+" <e2:MultiplicativeExpression> <le: @L> =>
|
||||||
@@ -205,18 +235,15 @@ UnaryExpression: Expression = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CallExpression: Expression = {
|
CallExpression: Expression = {
|
||||||
<s: @L> <f:CallExpression> "(" <args: CallArguments> ")" <e: @L> =>
|
<s: @L> <f:CallExpression> "(" <args: Comma<Expression>> ")" <e: @L> =>
|
||||||
Expression::Call(Location::new(file_idx, s..e), Box::new(f), args),
|
Expression::Call(Location::new(file_idx, s..e), Box::new(f), args),
|
||||||
AtomicExpression,
|
FieldExpression,
|
||||||
}
|
}
|
||||||
|
|
||||||
CallArguments: Vec<Expression> = {
|
FieldExpression: Expression = {
|
||||||
=> vec![],
|
<s: @L> <fe:FieldExpression> "." <field:Name> <e: @L> =>
|
||||||
<e:Expression> => vec![e],
|
Expression::FieldRef(Location::new(file_idx, s..e), Box::new(fe), field),
|
||||||
<mut args:CallArguments> "," <e:Expression> => {
|
AtomicExpression,
|
||||||
args.push(e);
|
|
||||||
args
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally, we describe our lowest-level expressions as "atomic", because
|
// finally, we describe our lowest-level expressions as "atomic", because
|
||||||
@@ -232,4 +259,16 @@ AtomicExpression: Expression = {
|
|||||||
// finally, let people parenthesize expressions and get back to a
|
// finally, let people parenthesize expressions and get back to a
|
||||||
// lower precedence
|
// lower precedence
|
||||||
"(" <e:Expression> ")" => e,
|
"(" <e:Expression> ")" => e,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lifted from the LALRPop book, a comma-separated list of T that may or
|
||||||
|
// may not conclude with a comma.
|
||||||
|
Comma<T>: Vec<T> = {
|
||||||
|
<mut v:(<T> ",")*> <e:T?> => match e {
|
||||||
|
None => v,
|
||||||
|
Some(e) => {
|
||||||
|
v.push(e);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::syntax::ast::{ConstantType, Expression, Program, Statement, TopLevel, Value};
|
use crate::syntax::ast::{ConstantType, Expression, Program, Statement, TopLevel, Type, Value};
|
||||||
use crate::util::pretty::{derived_display, Allocator};
|
use crate::util::pretty::{derived_display, Allocator};
|
||||||
use pretty::{DocAllocator, DocBuilder};
|
use pretty::{DocAllocator, DocBuilder};
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ impl TopLevel {
|
|||||||
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
match self {
|
match self {
|
||||||
TopLevel::Statement(stmt) => stmt.pretty(allocator),
|
TopLevel::Statement(stmt) => stmt.pretty(allocator),
|
||||||
TopLevel::Function(name, arg_names, body) => allocator
|
TopLevel::Function(name, args, rettype, body) => allocator
|
||||||
.text("function")
|
.text("function")
|
||||||
.append(allocator.space())
|
.append(allocator.space())
|
||||||
.append(
|
.append(
|
||||||
@@ -32,13 +32,61 @@ impl TopLevel {
|
|||||||
.append(
|
.append(
|
||||||
allocator
|
allocator
|
||||||
.intersperse(
|
.intersperse(
|
||||||
arg_names.iter().map(|x| allocator.text(x.to_string())),
|
args.iter().map(|(x, t)| {
|
||||||
|
allocator.text(x.to_string()).append(
|
||||||
|
t.as_ref()
|
||||||
|
.map(|t| {
|
||||||
|
allocator
|
||||||
|
.text(":")
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(t.pretty(allocator))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| allocator.nil()),
|
||||||
|
)
|
||||||
|
}),
|
||||||
allocator.text(","),
|
allocator.text(","),
|
||||||
)
|
)
|
||||||
.parens(),
|
.parens(),
|
||||||
)
|
)
|
||||||
|
.append(
|
||||||
|
rettype
|
||||||
|
.as_ref()
|
||||||
|
.map(|rettype| {
|
||||||
|
allocator
|
||||||
|
.space()
|
||||||
|
.append(allocator.text("->"))
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(rettype.pretty(allocator))
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| allocator.nil()),
|
||||||
|
)
|
||||||
.append(allocator.space())
|
.append(allocator.space())
|
||||||
.append(body.pretty(allocator)),
|
.append(body.pretty(allocator)),
|
||||||
|
TopLevel::Structure(_, name, fields) => allocator
|
||||||
|
.text("struct")
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(
|
||||||
|
name.as_ref()
|
||||||
|
.map(|x| allocator.text(x.to_string()))
|
||||||
|
.unwrap_or_else(|| allocator.nil()),
|
||||||
|
)
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(allocator.text("{"))
|
||||||
|
.append(allocator.hardline())
|
||||||
|
.append(
|
||||||
|
allocator
|
||||||
|
.concat(fields.iter().map(|(name, ty)| {
|
||||||
|
allocator
|
||||||
|
.text(name.to_string())
|
||||||
|
.append(allocator.text(":"))
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(ty.pretty(allocator))
|
||||||
|
.append(allocator.text(";"))
|
||||||
|
.append(allocator.hardline())
|
||||||
|
}))
|
||||||
|
.nest(2),
|
||||||
|
)
|
||||||
|
.append(allocator.text("}")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,7 +113,28 @@ impl Expression {
|
|||||||
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(_, val) => val.pretty(allocator),
|
Expression::Value(_, val) => val.pretty(allocator),
|
||||||
|
Expression::Constructor(_, name, fields) => allocator
|
||||||
|
.text(name.to_string())
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(
|
||||||
|
allocator
|
||||||
|
.concat(fields.iter().map(|(n, e)| {
|
||||||
|
allocator
|
||||||
|
.text(n.to_string())
|
||||||
|
.append(allocator.text(":"))
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(e.pretty(allocator))
|
||||||
|
.append(allocator.text(";"))
|
||||||
|
.append(allocator.hardline())
|
||||||
|
}))
|
||||||
|
.nest(2)
|
||||||
|
.braces(),
|
||||||
|
),
|
||||||
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
Expression::Reference(_, var) => allocator.text(var.to_string()),
|
||||||
|
Expression::FieldRef(_, val, field) => val
|
||||||
|
.pretty(allocator)
|
||||||
|
.append(allocator.text("."))
|
||||||
|
.append(allocator.text(field.to_string())),
|
||||||
Expression::Cast(_, t, e) => allocator
|
Expression::Cast(_, t, e) => allocator
|
||||||
.text(t.clone())
|
.text(t.clone())
|
||||||
.angles()
|
.angles()
|
||||||
@@ -151,6 +220,42 @@ fn type_suffix(x: &Option<ConstantType>) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Type {
|
||||||
|
pub fn pretty<'a>(&self, allocator: &'a Allocator<'a>) -> DocBuilder<'a, Allocator<'a>> {
|
||||||
|
match self {
|
||||||
|
Type::Named(x) => allocator.text(x.to_string()),
|
||||||
|
Type::Struct(name, fields) => allocator
|
||||||
|
.text("struct")
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(
|
||||||
|
name.as_ref()
|
||||||
|
.map(|x| allocator.text(x.to_string()))
|
||||||
|
.unwrap_or_else(|| allocator.nil()),
|
||||||
|
)
|
||||||
|
.append(allocator.intersperse(
|
||||||
|
fields.iter().map(|(name, ty)| {
|
||||||
|
allocator
|
||||||
|
.text(
|
||||||
|
name.as_ref()
|
||||||
|
.map(|x| x.to_string())
|
||||||
|
.unwrap_or_else(|| "_".to_string()),
|
||||||
|
)
|
||||||
|
.append(allocator.text(":"))
|
||||||
|
.append(allocator.space())
|
||||||
|
.append(
|
||||||
|
ty.as_ref()
|
||||||
|
.map(|x| x.pretty(allocator))
|
||||||
|
.unwrap_or_else(|| allocator.text("_")),
|
||||||
|
)
|
||||||
|
.append(allocator.text(";"))
|
||||||
|
}),
|
||||||
|
allocator.hardline(),
|
||||||
|
))
|
||||||
|
.braces(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
derived_display!(Program);
|
derived_display!(Program);
|
||||||
derived_display!(TopLevel);
|
derived_display!(TopLevel);
|
||||||
derived_display!(Statement);
|
derived_display!(Statement);
|
||||||
|
|||||||
@@ -36,12 +36,18 @@ pub enum Token {
|
|||||||
#[token("=")]
|
#[token("=")]
|
||||||
Equals,
|
Equals,
|
||||||
|
|
||||||
|
#[token(":")]
|
||||||
|
Colon,
|
||||||
|
|
||||||
#[token(";")]
|
#[token(";")]
|
||||||
Semi,
|
Semi,
|
||||||
|
|
||||||
#[token(",")]
|
#[token(",")]
|
||||||
Comma,
|
Comma,
|
||||||
|
|
||||||
|
#[token(".")]
|
||||||
|
Dot,
|
||||||
|
|
||||||
#[token("(")]
|
#[token("(")]
|
||||||
LeftParen,
|
LeftParen,
|
||||||
|
|
||||||
@@ -54,17 +60,26 @@ pub enum Token {
|
|||||||
#[token(">")]
|
#[token(">")]
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
|
|
||||||
|
#[token("_")]
|
||||||
|
Underscore,
|
||||||
|
|
||||||
#[token("{")]
|
#[token("{")]
|
||||||
OpenBrace,
|
OpenBrace,
|
||||||
|
|
||||||
#[token("}")]
|
#[token("}")]
|
||||||
CloseBrace,
|
CloseBrace,
|
||||||
|
|
||||||
|
#[token("->")]
|
||||||
|
SingleArrow,
|
||||||
|
|
||||||
#[token("λ")]
|
#[token("λ")]
|
||||||
#[token("lambda")]
|
#[token("lambda")]
|
||||||
#[token("function")]
|
#[token("function")]
|
||||||
Function,
|
Function,
|
||||||
|
|
||||||
|
#[token("struct")]
|
||||||
|
Struct,
|
||||||
|
|
||||||
// Next we take of any reserved words; I always like to put
|
// Next we take of any reserved words; I always like to put
|
||||||
// these before we start recognizing more complicated regular
|
// these before we start recognizing more complicated regular
|
||||||
// expressions. I don't think it matters, but it works for me.
|
// expressions. I don't think it matters, but it works for me.
|
||||||
@@ -93,21 +108,31 @@ pub enum Token {
|
|||||||
// letter, too.
|
// letter, too.
|
||||||
#[regex(r"[a-z][a-zA-Z0-9_]*", |v| ArcIntern::new(v.slice().to_string()))]
|
#[regex(r"[a-z][a-zA-Z0-9_]*", |v| ArcIntern::new(v.slice().to_string()))]
|
||||||
Variable(ArcIntern<String>),
|
Variable(ArcIntern<String>),
|
||||||
|
|
||||||
|
// Type names; these are like variables, but must start with a capital
|
||||||
|
// letter.
|
||||||
|
#[regex(r"[A-Z][a-zA-Z0-9_]*", |v| ArcIntern::new(v.slice().to_string()))]
|
||||||
|
TypeName(ArcIntern<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Token {
|
impl fmt::Display for Token {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Token::Equals => write!(f, "'='"),
|
Token::Equals => write!(f, "'='"),
|
||||||
|
Token::Colon => write!(f, "':'"),
|
||||||
Token::Semi => write!(f, "';'"),
|
Token::Semi => write!(f, "';'"),
|
||||||
Token::Comma => write!(f, "','"),
|
Token::Comma => write!(f, "','"),
|
||||||
|
Token::Dot => write!(f, "'.'"),
|
||||||
Token::LeftParen => write!(f, "'('"),
|
Token::LeftParen => write!(f, "'('"),
|
||||||
Token::RightParen => write!(f, "')'"),
|
Token::RightParen => write!(f, "')'"),
|
||||||
Token::LessThan => write!(f, "<"),
|
Token::LessThan => write!(f, "<"),
|
||||||
Token::GreaterThan => write!(f, ">"),
|
Token::GreaterThan => write!(f, ">"),
|
||||||
|
Token::Underscore => write!(f, "_"),
|
||||||
Token::OpenBrace => write!(f, "{{"),
|
Token::OpenBrace => write!(f, "{{"),
|
||||||
Token::CloseBrace => write!(f, "}}"),
|
Token::CloseBrace => write!(f, "}}"),
|
||||||
|
Token::SingleArrow => write!(f, "->"),
|
||||||
Token::Function => write!(f, "function"),
|
Token::Function => write!(f, "function"),
|
||||||
|
Token::Struct => write!(f, "struct"),
|
||||||
Token::Print => write!(f, "'print'"),
|
Token::Print => write!(f, "'print'"),
|
||||||
Token::Operator(c) => write!(f, "'{}'", c),
|
Token::Operator(c) => write!(f, "'{}'", c),
|
||||||
Token::Number((None, otype, v)) => write!(f, "'{}{}'", v, display_optional_type(otype)),
|
Token::Number((None, otype, v)) => write!(f, "'{}{}'", v, display_optional_type(otype)),
|
||||||
@@ -131,6 +156,7 @@ impl fmt::Display for Token {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
Token::Variable(s) => write!(f, "'{}'", s),
|
Token::Variable(s) => write!(f, "'{}'", s),
|
||||||
|
Token::TypeName(s) => write!(f, "'{}'", s),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl Program {
|
|||||||
/// actually a problem.
|
/// actually a problem.
|
||||||
pub fn validate(&self) -> (Vec<Error>, Vec<Warning>) {
|
pub fn validate(&self) -> (Vec<Error>, Vec<Warning>) {
|
||||||
let mut bound_variables = ScopedMap::new();
|
let mut bound_variables = ScopedMap::new();
|
||||||
println!("validate: {}", self);
|
println!("validate:\n{}", self);
|
||||||
self.validate_with_bindings(&mut bound_variables)
|
self.validate_with_bindings(&mut bound_variables)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ impl Program {
|
|||||||
let mut warnings = vec![];
|
let mut warnings = vec![];
|
||||||
|
|
||||||
for stmt in self.items.iter() {
|
for stmt in self.items.iter() {
|
||||||
if let TopLevel::Function(Some(name), _, _) = stmt {
|
if let TopLevel::Function(Some(name), _, _, _) = stmt {
|
||||||
bound_variables.insert(name.to_string(), name.location.clone());
|
bound_variables.insert(name.to_string(), name.location.clone());
|
||||||
}
|
}
|
||||||
let (mut new_errors, mut new_warnings) = stmt.validate_with_bindings(bound_variables);
|
let (mut new_errors, mut new_warnings) = stmt.validate_with_bindings(bound_variables);
|
||||||
@@ -120,12 +120,12 @@ impl TopLevel {
|
|||||||
bound_variables: &mut ScopedMap<String, Location>,
|
bound_variables: &mut ScopedMap<String, Location>,
|
||||||
) -> (Vec<Error>, Vec<Warning>) {
|
) -> (Vec<Error>, Vec<Warning>) {
|
||||||
match self {
|
match self {
|
||||||
TopLevel::Function(name, arguments, body) => {
|
TopLevel::Function(name, arguments, _, body) => {
|
||||||
bound_variables.new_scope();
|
bound_variables.new_scope();
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
bound_variables.insert(name.name.clone(), name.location.clone());
|
bound_variables.insert(name.name.clone(), name.location.clone());
|
||||||
}
|
}
|
||||||
for arg in arguments.iter() {
|
for (arg, _) in arguments.iter() {
|
||||||
bound_variables.insert(arg.name.clone(), arg.location.clone());
|
bound_variables.insert(arg.name.clone(), arg.location.clone());
|
||||||
}
|
}
|
||||||
let result = body.validate(bound_variables);
|
let result = body.validate(bound_variables);
|
||||||
@@ -133,6 +133,7 @@ impl TopLevel {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
TopLevel::Statement(stmt) => stmt.validate(bound_variables),
|
TopLevel::Statement(stmt) => stmt.validate(bound_variables),
|
||||||
|
TopLevel::Structure(_, _, _) => (vec![], vec![]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,11 +199,24 @@ impl Expression {
|
|||||||
) -> (Vec<Error>, Vec<Warning>) {
|
) -> (Vec<Error>, Vec<Warning>) {
|
||||||
match self {
|
match self {
|
||||||
Expression::Value(_, _) => (vec![], vec![]),
|
Expression::Value(_, _) => (vec![], vec![]),
|
||||||
|
Expression::Constructor(_, _, fields) => {
|
||||||
|
let mut errors = vec![];
|
||||||
|
let mut warnings = vec![];
|
||||||
|
|
||||||
|
for (_, expr) in fields.iter() {
|
||||||
|
let (mut e, mut w) = expr.validate(variable_map);
|
||||||
|
errors.append(&mut e);
|
||||||
|
warnings.append(&mut w);
|
||||||
|
}
|
||||||
|
|
||||||
|
(errors, warnings)
|
||||||
|
}
|
||||||
Expression::Reference(_, var) if variable_map.contains_key(var) => (vec![], vec![]),
|
Expression::Reference(_, var) if variable_map.contains_key(var) => (vec![], vec![]),
|
||||||
Expression::Reference(loc, var) => (
|
Expression::Reference(loc, var) => (
|
||||||
vec![Error::UnboundVariable(loc.clone(), var.clone())],
|
vec![Error::UnboundVariable(loc.clone(), var.clone())],
|
||||||
vec![],
|
vec![],
|
||||||
),
|
),
|
||||||
|
Expression::FieldRef(_, exp, _) => exp.validate(variable_map),
|
||||||
Expression::Cast(location, t, expr) => {
|
Expression::Cast(location, t, expr) => {
|
||||||
let (mut errs, warns) = expr.validate(variable_map);
|
let (mut errs, warns) = expr.validate(variable_map);
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ pub fn convert_top_level(
|
|||||||
bindings: &mut HashMap<ArcIntern<String>, ir::TypeOrVar>,
|
bindings: &mut HashMap<ArcIntern<String>, ir::TypeOrVar>,
|
||||||
) -> ir::TopLevel<ir::TypeOrVar> {
|
) -> ir::TopLevel<ir::TypeOrVar> {
|
||||||
match top_level {
|
match top_level {
|
||||||
syntax::TopLevel::Function(name, args, expr) => {
|
syntax::TopLevel::Function(name, args, _, expr) => {
|
||||||
// First, at some point we're going to want to know a location for this function,
|
// First, at some point we're going to want to know a location for this function,
|
||||||
// which should either be the name if we have one, or the body if we don't.
|
// which should either be the name if we have one, or the body if we don't.
|
||||||
let function_location = match name {
|
let function_location = match name {
|
||||||
@@ -76,7 +76,7 @@ pub fn convert_top_level(
|
|||||||
renames.new_scope();
|
renames.new_scope();
|
||||||
let arginfo = args
|
let arginfo = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|name| {
|
.map(|(name, _)| {
|
||||||
let new_type = ir::TypeOrVar::new();
|
let new_type = ir::TypeOrVar::new();
|
||||||
constraint_db.push(Constraint::IsSomething(
|
constraint_db.push(Constraint::IsSomething(
|
||||||
name.location.clone(),
|
name.location.clone(),
|
||||||
@@ -84,6 +84,7 @@ pub fn convert_top_level(
|
|||||||
));
|
));
|
||||||
let new_name = finalize_name(bindings, renames, name.clone());
|
let new_name = finalize_name(bindings, renames, name.clone());
|
||||||
bindings.insert(new_name.clone(), new_type.clone());
|
bindings.insert(new_name.clone(), new_type.clone());
|
||||||
|
unimplemented!();
|
||||||
(new_name, new_type)
|
(new_name, new_type)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@@ -119,6 +120,10 @@ pub fn convert_top_level(
|
|||||||
syntax::TopLevel::Statement(stmt) => {
|
syntax::TopLevel::Statement(stmt) => {
|
||||||
ir::TopLevel::Statement(convert_statement(stmt, constraint_db, renames, bindings))
|
ir::TopLevel::Statement(convert_statement(stmt, constraint_db, renames, bindings))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syntax::TopLevel::Structure(loc, oname, fields) => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +258,8 @@ fn convert_expression(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
syntax::Expression::Constructor(_, _, _) => unimplemented!(),
|
||||||
|
|
||||||
syntax::Expression::Reference(loc, name) => {
|
syntax::Expression::Reference(loc, name) => {
|
||||||
let iname = ArcIntern::new(name);
|
let iname = ArcIntern::new(name);
|
||||||
let final_name = renames.get(&iname).cloned().unwrap_or(iname);
|
let final_name = renames.get(&iname).cloned().unwrap_or(iname);
|
||||||
@@ -266,6 +273,8 @@ fn convert_expression(
|
|||||||
(refexp, rtype)
|
(refexp, rtype)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syntax::Expression::FieldRef(_, _, _) => unimplemented!(),
|
||||||
|
|
||||||
syntax::Expression::Cast(loc, target, expr) => {
|
syntax::Expression::Cast(loc, target, expr) => {
|
||||||
let (nexpr, etype) = convert_expression(*expr, constraint_db, renames, bindings);
|
let (nexpr, etype) = convert_expression(*expr, constraint_db, renames, bindings);
|
||||||
let (prereqs, val_or_ref) = simplify_expr(nexpr);
|
let (prereqs, val_or_ref) = simplify_expr(nexpr);
|
||||||
|
|||||||
Reference in New Issue
Block a user