Compare commits
8 Commits
b778428e98
...
4c99be700f
Author | SHA1 | Date | |
---|---|---|---|
|
4c99be700f | ||
|
2247d9b58e | ||
|
dcec8be307 | ||
|
934a390f2d | ||
|
8e8be1b449 | ||
|
5bfd79669e | ||
|
d913443e97 | ||
|
b5ec8116a2 |
@ -18,6 +18,7 @@ use crate::{
|
|||||||
derivative::Derivative,
|
derivative::Derivative,
|
||||||
identifier::{define_id_kind, Id},
|
identifier::{define_id_kind, Id},
|
||||||
parsing::Location,
|
parsing::Location,
|
||||||
|
util::delim_wrapped,
|
||||||
};
|
};
|
||||||
|
|
||||||
define_id_kind!(ASTItem);
|
define_id_kind!(ASTItem);
|
||||||
@ -40,12 +41,12 @@ impl fmt::Display for AST {
|
|||||||
|
|
||||||
#[derive(Derivative, Debug, Clone)]
|
#[derive(Derivative, Debug, Clone)]
|
||||||
#[derivative(PartialEq)]
|
#[derivative(PartialEq)]
|
||||||
pub struct Statement {
|
pub struct Statement<K> {
|
||||||
#[derivative(PartialEq = "ignore")]
|
#[derivative(PartialEq = "ignore")]
|
||||||
pub id: ItemId,
|
pub id: ItemId,
|
||||||
#[derivative(PartialEq = "ignore")]
|
#[derivative(PartialEq = "ignore")]
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
pub kind: StatementKind,
|
pub kind: K,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -65,23 +66,23 @@ pub enum FlowControl {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement<StatementKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<Statement>> for Block {
|
impl From<Vec<Statement<StatementKind>>> for Block {
|
||||||
fn from(statements: Vec<Statement>) -> Self {
|
fn from(statements: Vec<Statement<StatementKind>>) -> Self {
|
||||||
Self { statements }
|
Self { statements }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Statement> for Block {
|
impl From<Statement<StatementKind>> for Block {
|
||||||
fn from(statement: Statement) -> Self {
|
fn from(statement: Statement<StatementKind>) -> Self {
|
||||||
Self { statements: vec![statement] }
|
Self { statements: vec![statement] }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<[Statement]> for Block {
|
impl AsRef<[Statement<StatementKind>]> for Block {
|
||||||
fn as_ref(&self) -> &[Statement] {
|
fn as_ref(&self) -> &[Statement<StatementKind>] {
|
||||||
self.statements.as_ref()
|
self.statements.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,15 +124,41 @@ pub struct FormalParam {
|
|||||||
pub enum Declaration {
|
pub enum Declaration {
|
||||||
FuncSig(Signature),
|
FuncSig(Signature),
|
||||||
FuncDecl(Signature, Block),
|
FuncDecl(Signature, Block),
|
||||||
TypeDecl { name: TypeSingletonName, body: TypeBody, mutable: bool },
|
TypeDecl {
|
||||||
|
name: TypeSingletonName,
|
||||||
|
body: TypeBody,
|
||||||
|
mutable: bool,
|
||||||
|
},
|
||||||
//TODO TypeAlias `original` needs to be a more complex type definition
|
//TODO TypeAlias `original` needs to be a more complex type definition
|
||||||
TypeAlias { alias: Rc<String>, original: Rc<String> },
|
TypeAlias {
|
||||||
Binding { name: Rc<String>, constant: bool, type_anno: Option<TypeIdentifier>, expr: Expression },
|
alias: Rc<String>,
|
||||||
Impl { type_name: TypeIdentifier, interface_name: Option<TypeSingletonName>, block: Vec<Declaration> },
|
original: Rc<String>,
|
||||||
Interface { name: Rc<String>, signatures: Vec<Signature> },
|
},
|
||||||
|
Binding {
|
||||||
|
name: Rc<String>,
|
||||||
|
constant: bool,
|
||||||
|
type_anno: Option<TypeIdentifier>,
|
||||||
|
expr: Expression,
|
||||||
|
},
|
||||||
|
Impl {
|
||||||
|
type_name: TypeIdentifier,
|
||||||
|
interface_name: Option<TypeSingletonName>,
|
||||||
|
block: Vec<Statement<Declaration>>,
|
||||||
|
},
|
||||||
|
Interface {
|
||||||
|
name: Rc<String>,
|
||||||
|
signatures: Vec<Signature>,
|
||||||
|
},
|
||||||
//TODO need to limit the types of statements that can be annotated
|
//TODO need to limit the types of statements that can be annotated
|
||||||
Annotation { name: Rc<String>, arguments: Vec<Expression>, inner: Box<Statement> },
|
Annotation {
|
||||||
Module { name: Rc<String>, items: Block },
|
name: Rc<String>,
|
||||||
|
arguments: Vec<Expression>,
|
||||||
|
inner: Box<Statement<StatementKind>>,
|
||||||
|
},
|
||||||
|
Module {
|
||||||
|
name: Rc<String>,
|
||||||
|
items: Block,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
@ -192,6 +219,22 @@ pub enum TypeIdentifier {
|
|||||||
Singleton(TypeSingletonName),
|
Singleton(TypeSingletonName),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for TypeIdentifier {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
TypeIdentifier::Tuple(items) =>
|
||||||
|
write!(f, "{}", delim_wrapped('(', ')', items.iter().map(|item| item.to_string()))),
|
||||||
|
TypeIdentifier::Singleton(tsn) => {
|
||||||
|
write!(f, "{}", tsn.name)?;
|
||||||
|
if !tsn.params.is_empty() {
|
||||||
|
write!(f, "{}", delim_wrapped('<', '>', tsn.params.iter().map(|item| item.to_string())))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct TypeSingletonName {
|
pub struct TypeSingletonName {
|
||||||
pub name: Rc<String>,
|
pub name: Rc<String>,
|
||||||
|
@ -29,7 +29,7 @@ pub(super) fn render_ast(ast: &AST) -> String {
|
|||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_statement(stmt: &Statement, indent: usize, buf: &mut String) {
|
fn render_statement(stmt: &Statement<StatementKind>, indent: usize, buf: &mut String) {
|
||||||
use StatementKind::*;
|
use StatementKind::*;
|
||||||
do_indent(indent, buf);
|
do_indent(indent, buf);
|
||||||
match stmt.kind {
|
match stmt.kind {
|
||||||
|
@ -163,7 +163,7 @@ pub fn block(input: Span) -> ParseResult<Block> {
|
|||||||
context("block", map(block_template(many1(statement_delimiter), statement), |items| items.into()))(input)
|
context("block", map(block_template(many1(statement_delimiter), statement), |items| items.into()))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn statement(input: Span) -> ParseResult<Statement> {
|
fn statement(input: Span) -> ParseResult<Statement<StatementKind>> {
|
||||||
let (input, pos) = position(input)?;
|
let (input, pos) = position(input)?;
|
||||||
let location = pos.location_offset().into();
|
let location = pos.location_offset().into();
|
||||||
let id = fresh_id(&input);
|
let id = fresh_id(&input);
|
||||||
@ -243,8 +243,16 @@ fn implementation(input: Span) -> ParseResult<Declaration> {
|
|||||||
))(input)
|
))(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decl_block(input: Span) -> ParseResult<Vec<Declaration>> {
|
fn decl_block(input: Span) -> ParseResult<Vec<Statement<Declaration>>> {
|
||||||
block_template(many1(statement_delimiter), func_decl)(input)
|
context("decl-block", block_template(many1(statement_delimiter), func_decl_statement))(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn func_decl_statement(input: Span) -> ParseResult<Statement<Declaration>> {
|
||||||
|
let (input, pos) = position(input)?;
|
||||||
|
let location = pos.location_offset().into();
|
||||||
|
let id = fresh_id(&input);
|
||||||
|
let (rest, kind) = context("decl-statement", func_decl)(input)?;
|
||||||
|
Ok((rest, Statement { id, location, kind }))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interface(input: Span) -> ParseResult<Declaration> {
|
fn interface(input: Span) -> ParseResult<Declaration> {
|
||||||
|
@ -38,10 +38,10 @@ peg::parser! {
|
|||||||
"{" __ items:(statement(parser) ** delimiter()) delimiter()? __ "}" { items.into() } /
|
"{" __ items:(statement(parser) ** delimiter()) delimiter()? __ "}" { items.into() } /
|
||||||
"{" __ stmt:statement(parser) __ "}" { vec![stmt].into() }
|
"{" __ stmt:statement(parser) __ "}" { vec![stmt].into() }
|
||||||
|
|
||||||
rule block_item(parser: &mut Parser) -> Statement =
|
rule block_item(parser: &mut Parser) -> Statement<StatementKind> =
|
||||||
_ stmt:statement(parser) _ delimiter()+ { stmt }
|
_ stmt:statement(parser) _ delimiter()+ { stmt }
|
||||||
|
|
||||||
rule statement(parser: &mut Parser) -> Statement =
|
rule statement(parser: &mut Parser) -> Statement<StatementKind> =
|
||||||
_ pos:position!() kind:statement_kind(parser) _ { Statement { id: parser.fresh(), location: pos.into(), kind } }
|
_ pos:position!() kind:statement_kind(parser) _ { Statement { id: parser.fresh(), location: pos.into(), kind } }
|
||||||
|
|
||||||
rule statement_kind(parser: &mut Parser) -> StatementKind =
|
rule statement_kind(parser: &mut Parser) -> StatementKind =
|
||||||
@ -100,8 +100,11 @@ peg::parser! {
|
|||||||
Declaration::Impl { type_name, interface_name: None, block }
|
Declaration::Impl { type_name, interface_name: None, block }
|
||||||
}
|
}
|
||||||
|
|
||||||
rule decl_block(parser: &mut Parser) -> Vec<Declaration> =
|
rule decl_block(parser: &mut Parser) -> Vec<Statement<Declaration>> =
|
||||||
"{" __ decls:(func_declaration(parser) ** (delimiter()+)) delimiter()? __ "}" { decls }
|
"{" __ decls:(func_declaration_stmt(parser) ** (delimiter()+)) delimiter()? __ "}" { decls }
|
||||||
|
|
||||||
|
rule func_declaration_stmt(parser: &mut Parser) -> Statement<Declaration> =
|
||||||
|
pos:position!() decl:func_declaration(parser) { Statement { id: parser.fresh(), location: pos.into(), kind: decl } }
|
||||||
|
|
||||||
rule interface(parser: &mut Parser) -> Declaration =
|
rule interface(parser: &mut Parser) -> Declaration =
|
||||||
"interface" _ name:identifier() _ signatures:signature_block(parser) { Declaration::Interface { name: rc_string(name), signatures } }
|
"interface" _ name:identifier() _ signatures:signature_block(parser) { Declaration::Interface { name: rc_string(name), signatures } }
|
||||||
|
@ -21,11 +21,11 @@ fn strlit(s: &str) -> ExpressionKind {
|
|||||||
ExpressionKind::StringLiteral { s: Rc::new(s.to_string()), prefix: None }
|
ExpressionKind::StringLiteral { s: Rc::new(s.to_string()), prefix: None }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stmt(kind: StatementKind) -> Statement {
|
fn stmt<K>(kind: K) -> Statement<K> {
|
||||||
Statement { location: Location::default(), id: ItemId::default(), kind }
|
Statement { location: Location::default(), id: ItemId::default(), kind }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exst(kind: ExpressionKind) -> Statement {
|
fn exst(kind: ExpressionKind) -> Statement<StatementKind> {
|
||||||
Statement {
|
Statement {
|
||||||
location: Location::default(),
|
location: Location::default(),
|
||||||
id: ItemId::default(),
|
id: ItemId::default(),
|
||||||
@ -33,7 +33,7 @@ fn exst(kind: ExpressionKind) -> Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decl(declaration: Declaration) -> Statement {
|
fn decl(declaration: Declaration) -> Statement<StatementKind> {
|
||||||
Statement {
|
Statement {
|
||||||
location: Location::default(),
|
location: Location::default(),
|
||||||
id: ItemId::default(),
|
id: ItemId::default(),
|
||||||
@ -41,7 +41,7 @@ fn decl(declaration: Declaration) -> Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_decl(sig: Signature, stmts: Block) -> Statement {
|
fn fn_decl(sig: Signature, stmts: Block) -> Statement<StatementKind> {
|
||||||
Statement {
|
Statement {
|
||||||
kind: StatementKind::Declaration(Declaration::FuncDecl(sig, stmts)),
|
kind: StatementKind::Declaration(Declaration::FuncDecl(sig, stmts)),
|
||||||
location: Default::default(),
|
location: Default::default(),
|
||||||
@ -992,14 +992,14 @@ fn impls() {
|
|||||||
use Declaration::{FuncDecl, Impl};
|
use Declaration::{FuncDecl, Impl};
|
||||||
|
|
||||||
let block = vec![
|
let block = vec![
|
||||||
FuncDecl(
|
stmt(FuncDecl(
|
||||||
Signature { name: rc("yolo"), operator: false, params: vec![], type_anno: None },
|
Signature { name: rc("yolo"), operator: false, params: vec![], type_anno: None },
|
||||||
vec![].into(),
|
vec![].into(),
|
||||||
),
|
)),
|
||||||
FuncDecl(
|
stmt(FuncDecl(
|
||||||
Signature { name: rc("swagg"), operator: false, params: vec![], type_anno: None },
|
Signature { name: rc("swagg"), operator: false, params: vec![], type_anno: None },
|
||||||
vec![].into(),
|
vec![].into(),
|
||||||
),
|
)),
|
||||||
];
|
];
|
||||||
|
|
||||||
assert_ast!(
|
assert_ast!(
|
||||||
|
@ -51,9 +51,8 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id();
|
|
||||||
entrypoint.push(Statement::Binding {
|
entrypoint.push(Statement::Binding {
|
||||||
id: def_id,
|
id: symbol.def_id(),
|
||||||
constant: *constant,
|
constant: *constant,
|
||||||
expr: self.expression(expr),
|
expr: self.expression(expr),
|
||||||
});
|
});
|
||||||
@ -65,7 +64,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
ReducedIR { functions: self.functions, entrypoint }
|
ReducedIR { functions: self.functions, entrypoint }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top_level_definition(&mut self, statement: &ast::Statement) {
|
fn top_level_definition(&mut self, statement: &ast::Statement<ast::StatementKind>) {
|
||||||
let ast::Statement { id: item_id, kind, .. } = statement;
|
let ast::Statement { id: item_id, kind, .. } = statement;
|
||||||
match kind {
|
match kind {
|
||||||
ast::StatementKind::Expression(_expr) => {
|
ast::StatementKind::Expression(_expr) => {
|
||||||
@ -85,7 +84,10 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_internal_statement(&mut self, statement: &ast::Statement) -> Option<Statement> {
|
fn function_internal_statement(
|
||||||
|
&mut self,
|
||||||
|
statement: &ast::Statement<ast::StatementKind>,
|
||||||
|
) -> Option<Statement> {
|
||||||
let ast::Statement { id: item_id, kind, .. } = statement;
|
let ast::Statement { id: item_id, kind, .. } = statement;
|
||||||
match kind {
|
match kind {
|
||||||
ast::StatementKind::Expression(expr) => Some(Statement::Expression(self.expression(expr))),
|
ast::StatementKind::Expression(expr) => Some(Statement::Expression(self.expression(expr))),
|
||||||
@ -96,8 +98,11 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
}
|
}
|
||||||
ast::Declaration::Binding { constant, expr, .. } => {
|
ast::Declaration::Binding { constant, expr, .. } => {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id();
|
Some(Statement::Binding {
|
||||||
Some(Statement::Binding { id: def_id, constant: *constant, expr: self.expression(expr) })
|
id: symbol.def_id(),
|
||||||
|
constant: *constant,
|
||||||
|
expr: self.expression(expr),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
@ -115,16 +120,15 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
|
|
||||||
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
|
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id();
|
|
||||||
let function_def = FunctionDefinition { body: self.function_internal_block(statements) };
|
let function_def = FunctionDefinition { body: self.function_internal_block(statements) };
|
||||||
self.functions.insert(def_id, function_def);
|
self.functions.insert(symbol.def_id(), function_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self, expr: &ast::Expression) -> Expression {
|
fn expression(&mut self, expr: &ast::Expression) -> Expression {
|
||||||
use crate::ast::ExpressionKind::*;
|
use crate::ast::ExpressionKind::*;
|
||||||
|
|
||||||
match &expr.kind {
|
match &expr.kind {
|
||||||
SelfValue => panic!(),
|
SelfValue => Expression::Lookup(Lookup::SelfParam),
|
||||||
NatLiteral(n) => Expression::Literal(Literal::Nat(*n)),
|
NatLiteral(n) => Expression::Literal(Literal::Nat(*n)),
|
||||||
FloatLiteral(f) => Expression::Literal(Literal::Float(*f)),
|
FloatLiteral(f) => Expression::Literal(Literal::Float(*f)),
|
||||||
//TODO implement handling string literal prefixes
|
//TODO implement handling string literal prefixes
|
||||||
@ -133,10 +137,19 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
|||||||
BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs),
|
BinExp(binop, lhs, rhs) => self.binop(binop, lhs, rhs),
|
||||||
PrefixExp(op, arg) => self.prefix(op, arg),
|
PrefixExp(op, arg) => self.prefix(op, arg),
|
||||||
Value(qualified_name) => self.value(qualified_name),
|
Value(qualified_name) => self.value(qualified_name),
|
||||||
Call { f, arguments } => Expression::Call {
|
Call { f, arguments } => {
|
||||||
f: Box::new(self.expression(f)),
|
let f = self.expression(f);
|
||||||
args: arguments.iter().map(|arg| self.invocation_argument(arg)).collect(),
|
let args = arguments.iter().map(|arg| self.invocation_argument(arg)).collect();
|
||||||
},
|
//TODO need to have full type availability at this point to do this method lookup
|
||||||
|
//correctly
|
||||||
|
if let Expression::Access { name, expr } = f {
|
||||||
|
let def_id = unimplemented!();
|
||||||
|
let method = Expression::Lookup(Lookup::Function(def_id));
|
||||||
|
Expression::CallMethod { f: Box::new(method), args, self_expr: expr }
|
||||||
|
} else {
|
||||||
|
Expression::Call { f: Box::new(f), args }
|
||||||
|
}
|
||||||
|
}
|
||||||
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
|
TupleLiteral(exprs) => Expression::Tuple(exprs.iter().map(|e| self.expression(e)).collect()),
|
||||||
IfExpression { discriminator, body } =>
|
IfExpression { discriminator, body } =>
|
||||||
self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),
|
self.reduce_if_expression(discriminator.as_ref().map(|x| x.as_ref()), body),
|
||||||
|
@ -57,6 +57,7 @@ pub enum Expression {
|
|||||||
Access { name: String, expr: Box<Expression> },
|
Access { name: String, expr: Box<Expression> },
|
||||||
Callable(Callable),
|
Callable(Callable),
|
||||||
Call { f: Box<Expression>, args: Vec<Expression> },
|
Call { f: Box<Expression>, args: Vec<Expression> },
|
||||||
|
CallMethod { f: Box<Expression>, args: Vec<Expression>, self_expr: Box<Expression> },
|
||||||
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
|
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
|
||||||
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
|
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
|
||||||
Loop { cond: Box<Expression>, statements: Vec<Statement> },
|
Loop { cond: Box<Expression>, statements: Vec<Statement> },
|
||||||
@ -90,6 +91,7 @@ pub enum Lookup {
|
|||||||
GlobalVar(DefId),
|
GlobalVar(DefId),
|
||||||
Function(DefId),
|
Function(DefId),
|
||||||
Param(u8),
|
Param(u8),
|
||||||
|
SelfParam,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -35,6 +35,7 @@ pub enum SymbolError {
|
|||||||
DuplicateRecord { type_fqsn: Fqsn, location: Location, record: String, member: String },
|
DuplicateRecord { type_fqsn: Fqsn, location: Location, record: String, member: String },
|
||||||
UnknownAnnotation { name: String },
|
UnknownAnnotation { name: String },
|
||||||
BadAnnotation { name: String, msg: String },
|
BadAnnotation { name: String, msg: String },
|
||||||
|
BadImplBlockEntry,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{hash_map::Entry, HashMap, HashSet},
|
collections::{hash_map::Entry, HashMap, HashSet},
|
||||||
|
rc::Rc,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
|
|
||||||
fn add_from_scope(
|
fn add_from_scope(
|
||||||
&mut self,
|
&mut self,
|
||||||
statements: &[Statement],
|
statements: &[Statement<StatementKind>],
|
||||||
scope_stack: &mut Vec<ScopeSegment>,
|
scope_stack: &mut Vec<ScopeSegment>,
|
||||||
function_scope: bool,
|
function_scope: bool,
|
||||||
) -> Vec<SymbolError> {
|
) -> Vec<SymbolError> {
|
||||||
@ -75,11 +76,33 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
self.add_type_members(name, body, mutable, location, type_fqsn)
|
self.add_type_members(name, body, mutable, location, type_fqsn)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
Declaration::Impl { type_name, interface_name, block } => {
|
||||||
Declaration::Impl { type_name, body, .. } => {
|
let mut errors = vec![];
|
||||||
|
let new_scope = ScopeSegment::Name(Rc::new(format!("<impl-block>{}", type_name)));
|
||||||
|
scope_stack.push(new_scope);
|
||||||
|
|
||||||
},
|
for decl_stmt in block.iter() {
|
||||||
*/
|
let Statement { id, kind, location } = decl_stmt;
|
||||||
|
let location = *location;
|
||||||
|
match kind {
|
||||||
|
decl @ Declaration::FuncDecl(signature, body) => {
|
||||||
|
let output =
|
||||||
|
self.add_single_declaration(id, decl, location, scope_stack, true);
|
||||||
|
if let Err(e) = output {
|
||||||
|
errors.push(e);
|
||||||
|
};
|
||||||
|
let new_scope = ScopeSegment::Name(signature.name.clone());
|
||||||
|
scope_stack.push(new_scope);
|
||||||
|
let output = self.add_from_scope(body.as_ref(), scope_stack, true);
|
||||||
|
scope_stack.pop();
|
||||||
|
errors.extend(output.into_iter());
|
||||||
|
}
|
||||||
|
_other => errors.push(SymbolError::BadImplBlockEntry),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
scope_stack.pop();
|
||||||
|
errors
|
||||||
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
};
|
};
|
||||||
errors.extend(recursive_errs.into_iter());
|
errors.extend(recursive_errs.into_iter());
|
||||||
@ -98,7 +121,22 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
function_scope: bool,
|
function_scope: bool,
|
||||||
) -> Result<(), SymbolError> {
|
) -> Result<(), SymbolError> {
|
||||||
match kind {
|
match kind {
|
||||||
StatementKind::Declaration(Declaration::FuncSig(signature)) => {
|
StatementKind::Declaration(decl) =>
|
||||||
|
self.add_single_declaration(id, decl, location, scope_stack, function_scope),
|
||||||
|
_ => return Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_single_declaration(
|
||||||
|
&mut self,
|
||||||
|
id: &ItemId,
|
||||||
|
decl: &Declaration,
|
||||||
|
location: Location,
|
||||||
|
scope_stack: &[ScopeSegment],
|
||||||
|
function_scope: bool,
|
||||||
|
) -> Result<(), SymbolError> {
|
||||||
|
match decl {
|
||||||
|
Declaration::FuncSig(signature) => {
|
||||||
let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone());
|
let fq_function = Fqsn::from_scope_stack(scope_stack, signature.name.clone());
|
||||||
self.table
|
self.table
|
||||||
.fq_names
|
.fq_names
|
||||||
@ -109,7 +147,7 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
|
|
||||||
self.add_symbol(id, fq_function, SymbolSpec::Func { method: None });
|
self.add_symbol(id, fq_function, SymbolSpec::Func { method: None });
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::FuncDecl(signature, ..)) => {
|
Declaration::FuncDecl(signature, ..) => {
|
||||||
let fn_name = &signature.name;
|
let fn_name = &signature.name;
|
||||||
let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone());
|
let fq_function = Fqsn::from_scope_stack(scope_stack, fn_name.clone());
|
||||||
self.table
|
self.table
|
||||||
@ -121,11 +159,13 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
|
|
||||||
self.add_symbol(id, fq_function, SymbolSpec::Func { method: None });
|
self.add_symbol(id, fq_function, SymbolSpec::Func { method: None });
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::TypeDecl { name, .. }) => {
|
Declaration::TypeDecl { name, .. } => {
|
||||||
let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone());
|
let fq_type = Fqsn::from_scope_stack(scope_stack, name.name.clone());
|
||||||
self.table.types.register(fq_type, NameSpec { location, kind: TypeKind::Constructor })?;
|
self.table.types.register(fq_type, NameSpec { location, kind: TypeKind::Constructor })?;
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::Binding { name, .. }) => {
|
//TODO handle type aliases
|
||||||
|
Declaration::TypeAlias { .. } => (),
|
||||||
|
Declaration::Binding { name, .. } => {
|
||||||
let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone());
|
let fq_binding = Fqsn::from_scope_stack(scope_stack, name.clone());
|
||||||
self.table
|
self.table
|
||||||
.fq_names
|
.fq_names
|
||||||
@ -134,11 +174,14 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
self.add_symbol(id, fq_binding, SymbolSpec::GlobalBinding);
|
self.add_symbol(id, fq_binding, SymbolSpec::GlobalBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::Module { name, .. }) => {
|
//TODO implement interfaces
|
||||||
|
Declaration::Interface { .. } => (),
|
||||||
|
Declaration::Impl { .. } => (),
|
||||||
|
Declaration::Module { name, .. } => {
|
||||||
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
|
let fq_module = Fqsn::from_scope_stack(scope_stack, name.clone());
|
||||||
self.table.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?;
|
self.table.fq_names.register(fq_module, NameSpec { location, kind: NameKind::Module })?;
|
||||||
}
|
}
|
||||||
StatementKind::Declaration(Declaration::Annotation { name, arguments, inner }) => {
|
Declaration::Annotation { name, arguments, inner } => {
|
||||||
let inner = inner.as_ref();
|
let inner = inner.as_ref();
|
||||||
self.add_single_statement(
|
self.add_single_statement(
|
||||||
&inner.id,
|
&inner.id,
|
||||||
@ -149,7 +192,6 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
)?;
|
)?;
|
||||||
self.process_annotation(name.as_ref(), arguments.as_slice(), scope_stack, inner)?;
|
self.process_annotation(name.as_ref(), arguments.as_slice(), scope_stack, inner)?;
|
||||||
}
|
}
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -159,7 +201,7 @@ impl<'a> SymbolTablePopulator<'a> {
|
|||||||
name: &str,
|
name: &str,
|
||||||
arguments: &[Expression],
|
arguments: &[Expression],
|
||||||
scope_stack: &[ScopeSegment],
|
scope_stack: &[ScopeSegment],
|
||||||
inner: &Statement,
|
inner: &Statement<StatementKind>,
|
||||||
) -> Result<(), SymbolError> {
|
) -> Result<(), SymbolError> {
|
||||||
if name == "register_builtin" {
|
if name == "register_builtin" {
|
||||||
if let Statement {
|
if let Statement {
|
||||||
|
@ -15,19 +15,20 @@ enum NameType {
|
|||||||
Import(Fqsn),
|
Import(Fqsn),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LexScope<'a> = ScopeStack<'a, Rc<String>, NameType, ScopeType>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ScopeType {
|
enum ScopeType {
|
||||||
Function { name: Rc<String> },
|
Function { name: Rc<String> },
|
||||||
Lambda,
|
Lambda,
|
||||||
PatternMatch,
|
PatternMatch,
|
||||||
|
ImplBlock,
|
||||||
//TODO add some notion of a let-like scope?
|
//TODO add some notion of a let-like scope?
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScopeResolver<'a> {
|
pub struct ScopeResolver<'a> {
|
||||||
symbol_table: &'a mut super::SymbolTable,
|
symbol_table: &'a mut super::SymbolTable,
|
||||||
//TODO maybe this shouldn't be a scope stack, b/c the recursion behavior comes from multiple
|
lexical_scopes: LexScope<'a>,
|
||||||
//instances of ScopeResolver
|
|
||||||
lexical_scopes: ScopeStack<'a, Rc<String>, NameType, ScopeType>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ScopeResolver<'a> {
|
impl<'a> ScopeResolver<'a> {
|
||||||
@ -43,6 +44,7 @@ impl<'a> ScopeResolver<'a> {
|
|||||||
/// This method correctly modifies the id_to_def table (ItemId) to have the appropriate
|
/// This method correctly modifies the id_to_def table (ItemId) to have the appropriate
|
||||||
/// mappings.
|
/// mappings.
|
||||||
fn lookup_name_in_scope(&mut self, name: &QualifiedName) {
|
fn lookup_name_in_scope(&mut self, name: &QualifiedName) {
|
||||||
|
//TODO this method badly needs attention
|
||||||
let QualifiedName { id, components } = name;
|
let QualifiedName { id, components } = name;
|
||||||
|
|
||||||
let local_name = components.first().unwrap().clone();
|
let local_name = components.first().unwrap().clone();
|
||||||
@ -138,6 +140,8 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
let param_names = signature.params.iter().map(|param| param.name.clone());
|
let param_names = signature.params.iter().map(|param| param.name.clone());
|
||||||
//TODO I'm 90% sure this is right, until I get to closures
|
//TODO I'm 90% sure this is right, until I get to closures
|
||||||
//let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() }));
|
//let mut new_scope = self.lexical_scopes.new_scope(Some(ScopeType::Function { name: signature.name.clone() }));
|
||||||
|
//TODO this will recurse unwantedly into scopes; need to pop an outer function
|
||||||
|
//scope off first before going into a non-closure scope
|
||||||
let mut new_scope =
|
let mut new_scope =
|
||||||
ScopeStack::new(Some(ScopeType::Function { name: signature.name.clone() }));
|
ScopeStack::new(Some(ScopeType::Function { name: signature.name.clone() }));
|
||||||
|
|
||||||
@ -162,6 +166,15 @@ impl<'a> ASTVisitor for ScopeResolver<'a> {
|
|||||||
}
|
}
|
||||||
Recursion::Continue
|
Recursion::Continue
|
||||||
}
|
}
|
||||||
|
Declaration::Impl { block, .. } => {
|
||||||
|
let mut new_scope = ScopeStack::new(Some(ScopeType::ImplBlock));
|
||||||
|
let mut new_resolver =
|
||||||
|
ScopeResolver { symbol_table: self.symbol_table, lexical_scopes: new_scope };
|
||||||
|
for stmt in block.iter() {
|
||||||
|
walk_declaration(&mut new_resolver, &stmt.kind, &stmt.id);
|
||||||
|
}
|
||||||
|
Recursion::Stop
|
||||||
|
}
|
||||||
_ => Recursion::Continue,
|
_ => Recursion::Continue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -271,9 +271,27 @@ fn duplicate_struct_members() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
#[test]
|
||||||
fn methods() {
|
fn method_definition_added_to_symbol_table() {
|
||||||
|
let source = r#"
|
||||||
|
|
||||||
|
type Foo = { x: Int, y: Int }
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn hella() {
|
||||||
|
let a = 50
|
||||||
|
self.x + a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let (symbols, _) = add_symbols(source);
|
||||||
|
symbols.debug();
|
||||||
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["<impl-block>Foo", "hella"])).is_some());
|
||||||
|
assert!(symbols.fq_names.table.get(&make_fqsn(&["<impl-block>Foo", "hella", "a"])).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn duplicate_method_definitions_detected() {
|
||||||
let source = r#"
|
let source = r#"
|
||||||
|
|
||||||
type Foo = { x: Int, y: Int }
|
type Foo = { x: Int, y: Int }
|
||||||
@ -282,10 +300,15 @@ impl Foo {
|
|||||||
fn hella() {
|
fn hella() {
|
||||||
self.x + 50
|
self.x + 50
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hella() {
|
||||||
|
self.x + 40
|
||||||
|
}
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
let (symbols, _) = add_symbols(source);
|
let (_symbols, output) = add_symbols(source);
|
||||||
symbols.debug();
|
let errs = output.unwrap_err();
|
||||||
assert!(symbols.fq_names.table.get(&make_fqsn(&["hella"])).is_some());
|
assert_matches!(&errs[..], [
|
||||||
|
SymbolError::DuplicateName { prev_name: pn1, ..},
|
||||||
|
] if pn1 == &Fqsn::from_strs(&["<impl-block>Foo", "hella"]));
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
@ -38,7 +38,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
let mut acc = vec![];
|
let mut acc = vec![];
|
||||||
for (def_id, function) in reduced.functions.into_iter() {
|
for (def_id, function) in reduced.functions.into_iter() {
|
||||||
let mem = (&def_id).into();
|
let mem = (&def_id).into();
|
||||||
self.state.environments.insert(mem, MemoryValue::Function(function));
|
self.state.memory.insert(mem, MemoryValue::Function(function));
|
||||||
}
|
}
|
||||||
|
|
||||||
for statement in reduced.entrypoint.into_iter() {
|
for statement in reduced.entrypoint.into_iter() {
|
||||||
@ -78,7 +78,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
match stmt {
|
match stmt {
|
||||||
Statement::Binding { ref id, expr, constant: _ } => {
|
Statement::Binding { ref id, expr, constant: _ } => {
|
||||||
let evaluated = self.expression(expr)?;
|
let evaluated = self.expression(expr)?;
|
||||||
self.state.environments.insert(id.into(), evaluated.into());
|
self.state.memory.insert(id.into(), evaluated.into());
|
||||||
Ok(StatementOutput::Nothing)
|
Ok(StatementOutput::Nothing)
|
||||||
}
|
}
|
||||||
Statement::Expression(expr) => {
|
Statement::Expression(expr) => {
|
||||||
@ -119,7 +119,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
Expression::Lookup(kind) => match kind {
|
Expression::Lookup(kind) => match kind {
|
||||||
Lookup::Function(ref id) => {
|
Lookup::Function(ref id) => {
|
||||||
let mem = id.into();
|
let mem = id.into();
|
||||||
match self.state.environments.lookup(&mem) {
|
match self.state.memory.lookup(&mem) {
|
||||||
// This just checks that the function exists in "memory" by ID, we don't
|
// This just checks that the function exists in "memory" by ID, we don't
|
||||||
// actually retrieve it until `apply_function()`
|
// actually retrieve it until `apply_function()`
|
||||||
Some(MemoryValue::Function(_)) => Primitive::Callable(Callable::UserDefined(*id)),
|
Some(MemoryValue::Function(_)) => Primitive::Callable(Callable::UserDefined(*id)),
|
||||||
@ -128,14 +128,21 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
}
|
}
|
||||||
Lookup::Param(n) => {
|
Lookup::Param(n) => {
|
||||||
let mem = n.into();
|
let mem = n.into();
|
||||||
match self.state.environments.lookup(&mem) {
|
match self.state.memory.lookup(&mem) {
|
||||||
Some(MemoryValue::Primitive(prim)) => prim.clone(),
|
Some(MemoryValue::Primitive(prim)) => prim.clone(),
|
||||||
e => return Err(format!("Param lookup error, got {:?}", e).into()),
|
e => return Err(format!("Param lookup error, got {:?}", e).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Lookup::SelfParam => {
|
||||||
|
let mem = Memory::self_param();
|
||||||
|
match self.state.memory.lookup(&mem) {
|
||||||
|
Some(MemoryValue::Primitive(prim)) => prim.clone(),
|
||||||
|
e => return Err(format!("SelfParam lookup error, got {:?}", e).into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
Lookup::LocalVar(ref id) | Lookup::GlobalVar(ref id) => {
|
Lookup::LocalVar(ref id) | Lookup::GlobalVar(ref id) => {
|
||||||
let mem = id.into();
|
let mem = id.into();
|
||||||
match self.state.environments.lookup(&mem) {
|
match self.state.memory.lookup(&mem) {
|
||||||
Some(MemoryValue::Primitive(expr)) => expr.clone(),
|
Some(MemoryValue::Primitive(expr)) => expr.clone(),
|
||||||
_ =>
|
_ =>
|
||||||
return Err(
|
return Err(
|
||||||
@ -148,10 +155,12 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
let mem = lval.into();
|
let mem = lval.into();
|
||||||
let evaluated = self.expression(rval)?;
|
let evaluated = self.expression(rval)?;
|
||||||
println!("Inserting {:?} into {:?}", evaluated, mem);
|
println!("Inserting {:?} into {:?}", evaluated, mem);
|
||||||
self.state.environments.insert(mem, MemoryValue::Primitive(evaluated));
|
self.state.memory.insert(mem, MemoryValue::Primitive(evaluated));
|
||||||
Primitive::unit()
|
Primitive::unit()
|
||||||
}
|
}
|
||||||
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
Expression::Call { box f, args } => self.call_expression(f, args, None)?,
|
||||||
|
Expression::CallMethod { box f, args, box self_expr } =>
|
||||||
|
self.call_expression(f, args, Some(self_expr))?,
|
||||||
Expression::Callable(Callable::DataConstructor { type_id, tag }) => {
|
Expression::Callable(Callable::DataConstructor { type_id, tag }) => {
|
||||||
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
||||||
if arity == 0 {
|
if arity == 0 {
|
||||||
@ -302,9 +311,9 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
let cond = self.expression(cond)?;
|
let cond = self.expression(cond)?;
|
||||||
|
|
||||||
for alt in alternatives.into_iter() {
|
for alt in alternatives.into_iter() {
|
||||||
let mut new_scope = self.state.environments.new_scope(None);
|
let mut new_scope = self.state.memory.new_scope(None);
|
||||||
if matches(&cond, &alt.pattern, &mut new_scope) {
|
if matches(&cond, &alt.pattern, &mut new_scope) {
|
||||||
let mut new_state = State { environments: new_scope };
|
let mut new_state = State { memory: new_scope };
|
||||||
let mut evaluator = Evaluator::new(&mut new_state, self.type_context);
|
let mut evaluator = Evaluator::new(&mut new_state, self.type_context);
|
||||||
let output = evaluator.block(alt.item);
|
let output = evaluator.block(alt.item);
|
||||||
self.early_returning = evaluator.early_returning;
|
self.early_returning = evaluator.early_returning;
|
||||||
@ -314,7 +323,13 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
Err("No valid match in match expression".into())
|
Err("No valid match in match expression".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
|
//TODO need to do something with self_expr to make method invocations actually work
|
||||||
|
fn call_expression(
|
||||||
|
&mut self,
|
||||||
|
f: Expression,
|
||||||
|
args: Vec<Expression>,
|
||||||
|
self_expr: Option<Expression>,
|
||||||
|
) -> EvalResult<Primitive> {
|
||||||
let func = match self.expression(f)? {
|
let func = match self.expression(f)? {
|
||||||
Primitive::Callable(func) => func,
|
Primitive::Callable(func) => func,
|
||||||
other => return Err(format!("Trying to call non-function value: {:?}", other).into()),
|
other => return Err(format!("Trying to call non-function value: {:?}", other).into()),
|
||||||
@ -323,10 +338,10 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
Callable::Builtin(builtin) => self.apply_builtin(builtin, args),
|
Callable::Builtin(builtin) => self.apply_builtin(builtin, args),
|
||||||
Callable::UserDefined(def_id) => {
|
Callable::UserDefined(def_id) => {
|
||||||
let mem = (&def_id).into();
|
let mem = (&def_id).into();
|
||||||
match self.state.environments.lookup(&mem) {
|
match self.state.memory.lookup(&mem) {
|
||||||
Some(MemoryValue::Function(FunctionDefinition { body })) => {
|
Some(MemoryValue::Function(FunctionDefinition { body })) => {
|
||||||
let body = body.clone(); //TODO ideally this clone would not happen
|
let body = body.clone(); //TODO ideally this clone would not happen
|
||||||
self.apply_function(body, args)
|
self.apply_function(body, args, self_expr)
|
||||||
}
|
}
|
||||||
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into()),
|
e => Err(format!("Error looking up function with id {}: {:?}", def_id, e).into()),
|
||||||
}
|
}
|
||||||
@ -340,7 +355,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
)
|
)
|
||||||
.into());
|
.into());
|
||||||
}
|
}
|
||||||
self.apply_function(body, args)
|
self.apply_function(body, args, None)
|
||||||
}
|
}
|
||||||
Callable::DataConstructor { type_id, tag } => {
|
Callable::DataConstructor { type_id, tag } => {
|
||||||
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
let arity = self.type_context.lookup_variant_arity(&type_id, tag).unwrap();
|
||||||
@ -469,21 +484,30 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_function(&mut self, body: Vec<Statement>, args: Vec<Expression>) -> EvalResult<Primitive> {
|
fn apply_function(
|
||||||
|
&mut self,
|
||||||
|
body: Vec<Statement>,
|
||||||
|
args: Vec<Expression>,
|
||||||
|
self_expr: Option<Expression>,
|
||||||
|
) -> EvalResult<Primitive> {
|
||||||
|
let self_expr = if let Some(expr) = self_expr { Some(self.expression(expr)?) } else { None };
|
||||||
let mut evaluated_args: Vec<Primitive> = vec![];
|
let mut evaluated_args: Vec<Primitive> = vec![];
|
||||||
for arg in args.into_iter() {
|
for arg in args.into_iter() {
|
||||||
evaluated_args.push(self.expression(arg)?);
|
evaluated_args.push(self.expression(arg)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut frame_state = State { environments: self.state.environments.new_scope(None) };
|
let mut frame_state = State { memory: self.state.memory.new_scope(None) };
|
||||||
let mut evaluator = Evaluator::new(&mut frame_state, self.type_context);
|
let mut evaluator = Evaluator::new(&mut frame_state, self.type_context);
|
||||||
|
|
||||||
|
if let Some(evaled) = self_expr {
|
||||||
|
let mem = Memory::self_param();
|
||||||
|
evaluator.state.memory.insert(mem, MemoryValue::Primitive(evaled));
|
||||||
|
}
|
||||||
for (n, evaled) in evaluated_args.into_iter().enumerate() {
|
for (n, evaled) in evaluated_args.into_iter().enumerate() {
|
||||||
let n = n as u8;
|
let n = n as u8;
|
||||||
let mem = n.into();
|
let mem = n.into();
|
||||||
evaluator.state.environments.insert(mem, MemoryValue::Primitive(evaled));
|
evaluator.state.memory.insert(mem, MemoryValue::Primitive(evaled));
|
||||||
}
|
}
|
||||||
|
|
||||||
evaluator.block(body)
|
evaluator.block(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
reduced_ir::{Callable, Expression, FunctionDefinition, Literal, ReducedIR},
|
reduced_ir::{Callable, Expression, FunctionDefinition, Literal, ReducedIR},
|
||||||
symbol_table::DefId,
|
symbol_table::DefId,
|
||||||
type_inference::{TypeContext, TypeId},
|
type_inference::{TypeContext, TypeId},
|
||||||
util::ScopeStack,
|
util::{delim_wrapped, ScopeStack},
|
||||||
};
|
};
|
||||||
|
|
||||||
mod evaluator;
|
mod evaluator;
|
||||||
@ -14,7 +14,7 @@ type EvalResult<T> = Result<T, RuntimeError>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
environments: ScopeStack<'a, Memory, MemoryValue>,
|
memory: ScopeStack<'a, Memory, MemoryValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO - eh, I dunno, maybe it doesn't matter exactly how memory works in the tree-walking
|
//TODO - eh, I dunno, maybe it doesn't matter exactly how memory works in the tree-walking
|
||||||
@ -24,6 +24,12 @@ enum Memory {
|
|||||||
Index(u32),
|
Index(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Memory {
|
||||||
|
fn self_param() -> Self {
|
||||||
|
Memory::Index(3_999_999)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is for function param lookups, and is a hack
|
// This is for function param lookups, and is a hack
|
||||||
impl From<u8> for Memory {
|
impl From<u8> for Memory {
|
||||||
fn from(n: u8) -> Self {
|
fn from(n: u8) -> Self {
|
||||||
@ -61,19 +67,6 @@ impl RuntimeError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delim_wrapped(lhs: char, rhs: char, terms: impl Iterator<Item = String>) -> String {
|
|
||||||
let mut buf = String::new();
|
|
||||||
write!(buf, "{}", lhs).unwrap();
|
|
||||||
for term in terms.map(Some).intersperse(None) {
|
|
||||||
match term {
|
|
||||||
Some(e) => write!(buf, "{}", e).unwrap(),
|
|
||||||
None => write!(buf, ", ").unwrap(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
write!(buf, "{}", rhs).unwrap();
|
|
||||||
buf
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Anything that can be stored in memory; that is, a function definition, or a fully-evaluated
|
/// Anything that can be stored in memory; that is, a function definition, or a fully-evaluated
|
||||||
/// program value.
|
/// program value.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -165,7 +158,7 @@ impl From<Literal> for Primitive {
|
|||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { environments: ScopeStack::new(Some("global".to_string())) }
|
Self { memory: ScopeStack::new(Some("global".to_string())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evaluate(
|
pub fn evaluate(
|
||||||
|
@ -1,4 +1,18 @@
|
|||||||
use std::{cmp::Eq, collections::HashMap, hash::Hash};
|
use std::{cmp::Eq, collections::HashMap, fmt::Write, hash::Hash};
|
||||||
|
|
||||||
|
/// Utility function for printing a comma-delimited list of things
|
||||||
|
pub(crate) fn delim_wrapped(lhs: char, rhs: char, terms: impl Iterator<Item = String>) -> String {
|
||||||
|
let mut buf = String::new();
|
||||||
|
write!(buf, "{}", lhs).unwrap();
|
||||||
|
for term in terms.map(Some).intersperse(None) {
|
||||||
|
match term {
|
||||||
|
Some(e) => write!(buf, "{}", e).unwrap(),
|
||||||
|
None => write!(buf, ", ").unwrap(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
write!(buf, "{}", rhs).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ScopeStack<'a, T: 'a, V: 'a, N = String>
|
pub struct ScopeStack<'a, T: 'a, V: 'a, N = String>
|
||||||
|
Loading…
Reference in New Issue
Block a user