Start work on qualified names
This commit is contained in:
parent
89d967aee4
commit
34abb9b081
@ -46,6 +46,9 @@ pub enum Statement {
|
|||||||
pub type Block = Vec<Meta<Statement>>;
|
pub type Block = Vec<Meta<Statement>>;
|
||||||
pub type ParamName = Rc<String>;
|
pub type ParamName = Rc<String>;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct QualifiedName(pub Vec<Rc<String>>);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct FormalParam {
|
pub struct FormalParam {
|
||||||
pub name: ParamName,
|
pub name: ParamName,
|
||||||
@ -138,9 +141,9 @@ pub enum ExpressionKind {
|
|||||||
BinExp(BinOp, Box<Meta<Expression>>, Box<Meta<Expression>>),
|
BinExp(BinOp, Box<Meta<Expression>>, Box<Meta<Expression>>),
|
||||||
PrefixExp(PrefixOp, Box<Meta<Expression>>),
|
PrefixExp(PrefixOp, Box<Meta<Expression>>),
|
||||||
TupleLiteral(Vec<Meta<Expression>>),
|
TupleLiteral(Vec<Meta<Expression>>),
|
||||||
Value(Rc<String>),
|
Value(QualifiedName),
|
||||||
NamedStruct {
|
NamedStruct {
|
||||||
name: Rc<String>,
|
name: QualifiedName,
|
||||||
fields: Vec<(Rc<String>, Meta<Expression>)>,
|
fields: Vec<(Rc<String>, Meta<Expression>)>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
|
@ -85,13 +85,14 @@
|
|||||||
//! lambda_param_list := formal_param_list | formal_param
|
//! lambda_param_list := formal_param_list | formal_param
|
||||||
//! paren_expr := "(" paren_inner ")"
|
//! paren_expr := "(" paren_inner ")"
|
||||||
//! paren_inner := (expression ",")*
|
//! paren_inner := (expression ",")*
|
||||||
//! identifier_expr := named_struct | IDENTIFIER
|
//! identifier_expr := qualified_identifier | named_struct
|
||||||
|
//! qualified_identifier := IDENTIFIER ("::" IDENTIFIER)*
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! ## Literals
|
//! ## Literals
|
||||||
//! ```text
|
//! ```text
|
||||||
//! literal := "true" | "false" | number_literal | STR_LITERAL
|
//! literal := "true" | "false" | number_literal | STR_LITERAL
|
||||||
//! named_struct := IDENTIFIER record_block
|
//! named_struct := qualified_identifier record_block
|
||||||
//! record_block := "{" (record_entry, ",")* | "}" //TODO support anonymus structs, update syntax
|
//! record_block := "{" (record_entry, ",")* | "}" //TODO support anonymus structs, update syntax
|
||||||
//! record_entry := IDENTIFIER ":" expression
|
//! record_entry := IDENTIFIER ":" expression
|
||||||
//! anonymous_struct := TODO
|
//! anonymous_struct := TODO
|
||||||
@ -213,6 +214,7 @@ impl TokenHandler {
|
|||||||
fn peek(&mut self) -> Token {
|
fn peek(&mut self) -> Token {
|
||||||
self.tokens.get(self.idx).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
|
self.tokens.get(self.idx).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
|
||||||
}
|
}
|
||||||
|
/// calling peek_n(0) is the same thing as peek()
|
||||||
fn peek_n(&mut self, n: usize) -> Token {
|
fn peek_n(&mut self, n: usize) -> Token {
|
||||||
self.tokens.get(self.idx + n).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
|
self.tokens.get(self.idx + n).map(|t: &Token| { t.clone()}).unwrap_or(Token { kind: TokenKind::EOF, line_num: self.end_of_file.0, char_num: self.end_of_file.1})
|
||||||
}
|
}
|
||||||
@ -757,16 +759,31 @@ impl Parser {
|
|||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
fn identifier_expr(&mut self) -> ParseResult<Expression> {
|
fn identifier_expr(&mut self) -> ParseResult<Expression> {
|
||||||
use self::ExpressionKind::*;
|
use self::ExpressionKind::*;
|
||||||
let identifier = self.identifier()?;
|
let qualified_identifier = self.qualified_identifier()?;
|
||||||
Ok(match self.token_handler.peek_kind() {
|
Ok(match self.token_handler.peek_kind() {
|
||||||
LCurlyBrace if !self.restrictions.no_struct_literal => {
|
LCurlyBrace if !self.restrictions.no_struct_literal => {
|
||||||
let fields = self.record_block()?;
|
let fields = self.record_block()?;
|
||||||
Expression::new(NamedStruct { name: identifier, fields })
|
Expression::new(NamedStruct { name: qualified_identifier, fields })
|
||||||
},
|
},
|
||||||
_ => Expression::new(Value(identifier))
|
_ => Expression::new(Value(qualified_identifier))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[recursive_descent_method]
|
||||||
|
fn qualified_identifier(&mut self) -> ParseResult<QualifiedName> {
|
||||||
|
let mut vec = vec![self.identifier()?];
|
||||||
|
loop {
|
||||||
|
match (self.token_handler.peek_kind(), self.token_handler.peek_kind_n(1)) {
|
||||||
|
(Colon, Colon) => {
|
||||||
|
self.token_handler.next(); self.token_handler.next();
|
||||||
|
vec.push(self.identifier()?);
|
||||||
|
},
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(QualifiedName(vec))
|
||||||
|
}
|
||||||
|
|
||||||
#[recursive_descent_method]
|
#[recursive_descent_method]
|
||||||
fn record_block(&mut self) -> ParseResult<Vec<(Rc<String>, Meta<Expression>)>> {
|
fn record_block(&mut self) -> ParseResult<Vec<(Rc<String>, Meta<Expression>)>> {
|
||||||
Ok(
|
Ok(
|
||||||
|
@ -4,7 +4,7 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
use super::tokenize;
|
use super::tokenize;
|
||||||
use super::ParseResult;
|
use super::ParseResult;
|
||||||
use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp};
|
use crate::ast::{AST, Meta, Expression, Statement, IfExpressionBody, Discriminator, Pattern, PatternLiteral, TypeBody, Enumerator, ForBody, InvocationArgument, FormalParam, PrefixOp, BinOp, QualifiedName};
|
||||||
use super::Statement::*;
|
use super::Statement::*;
|
||||||
use super::Declaration::*;
|
use super::Declaration::*;
|
||||||
use super::Signature;
|
use super::Signature;
|
||||||
@ -30,7 +30,7 @@ macro_rules! parse_error {
|
|||||||
($string:expr) => { assert!(parse($string).is_err()) }
|
($string:expr) => { assert!(parse($string).is_err()) }
|
||||||
}
|
}
|
||||||
macro_rules! val {
|
macro_rules! val {
|
||||||
($var:expr) => { Value(Rc::new($var.to_string())) }
|
($var:expr) => { Value(QualifiedName(vec![Rc::new($var.to_string())])) };
|
||||||
}
|
}
|
||||||
macro_rules! ty {
|
macro_rules! ty {
|
||||||
($name:expr) => { Singleton(tys!($name)) }
|
($name:expr) => { Singleton(tys!($name)) }
|
||||||
@ -153,11 +153,11 @@ fn parsing_identifiers() {
|
|||||||
|
|
||||||
parse_test!("None", AST(vec![exst!(val!("None"))]));
|
parse_test!("None", AST(vec![exst!(val!("None"))]));
|
||||||
parse_test!("Pandas { a: x + y }", AST(vec![
|
parse_test!("Pandas { a: x + y }", AST(vec![
|
||||||
exst!(NamedStruct { name: rc!(Pandas), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]})
|
exst!(NamedStruct { name: QualifiedName(vec![rc!(Pandas)]), fields: vec![(rc!(a), ex!(m binexp!("+", val!("x"), val!("y"))))]})
|
||||||
]));
|
]));
|
||||||
parse_test! { "Pandas { a: n, b: q, }",
|
parse_test! { "Pandas { a: n, b: q, }",
|
||||||
AST(vec![
|
AST(vec![
|
||||||
exst!(NamedStruct { name: rc!(Pandas), fields:
|
exst!(NamedStruct { name: QualifiedName(vec![rc!(Pandas)]), fields:
|
||||||
vec![(rc!(a), ex!(m val!("n"))), (rc!(b), ex!(m val!("q")))]
|
vec![(rc!(a), ex!(m val!("n"))), (rc!(b), ex!(m val!("q")))]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -16,7 +16,7 @@ use std::rc::Rc;
|
|||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable};
|
use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable, ScopeSegment, ScopeSegmentKind, FullyQualifiedSymbolName};
|
||||||
use crate::builtin::Builtin;
|
use crate::builtin::Builtin;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -142,6 +142,21 @@ impl InvocationArgument {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO this is incomplete
|
||||||
|
fn lookup_name_in_scope(sym_name: &QualifiedName) -> FullyQualifiedSymbolName {
|
||||||
|
let QualifiedName(vec) = sym_name;
|
||||||
|
let len = vec.len();
|
||||||
|
let new_vec: Vec<ScopeSegment> = vec.iter().enumerate().map(|(i, name)| {
|
||||||
|
let kind = if i == (len - 1) {
|
||||||
|
ScopeSegmentKind::Terminal
|
||||||
|
} else {
|
||||||
|
ScopeSegmentKind::Type
|
||||||
|
};
|
||||||
|
ScopeSegment { name: name.clone(), kind }
|
||||||
|
}).collect();
|
||||||
|
FullyQualifiedSymbolName(new_vec)
|
||||||
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
fn reduce(&self, symbol_table: &SymbolTable) -> Expr {
|
fn reduce(&self, symbol_table: &SymbolTable) -> Expr {
|
||||||
use crate::ast::ExpressionKind::*;
|
use crate::ast::ExpressionKind::*;
|
||||||
@ -153,14 +168,19 @@ impl Expression {
|
|||||||
BoolLiteral(b) => Expr::Lit(Lit::Bool(*b)),
|
BoolLiteral(b) => Expr::Lit(Lit::Bool(*b)),
|
||||||
BinExp(binop, lhs, rhs) => binop.reduce(symbol_table, lhs, rhs),
|
BinExp(binop, lhs, rhs) => binop.reduce(symbol_table, lhs, rhs),
|
||||||
PrefixExp(op, arg) => op.reduce(symbol_table, arg),
|
PrefixExp(op, arg) => op.reduce(symbol_table, arg),
|
||||||
Value(name) => match symbol_table.lookup_by_name(name) {
|
Value(qualified_name) => {
|
||||||
Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
|
let sym_name = lookup_name_in_scope(&qualified_name);
|
||||||
type_name: type_name.clone(),
|
let FullyQualifiedSymbolName(ref v) = sym_name;
|
||||||
name: name.clone(),
|
let name = v.last().unwrap().name.clone();
|
||||||
tag: index.clone(),
|
match symbol_table.lookup_by_fqsn(&sym_name) {
|
||||||
arity: type_args.len(),
|
Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
|
||||||
},
|
type_name: type_name.clone(),
|
||||||
_ => Expr::Sym(name.clone()),
|
name: name.clone(),
|
||||||
|
tag: index.clone(),
|
||||||
|
arity: type_args.len(),
|
||||||
|
},
|
||||||
|
_ => Expr::Sym(name.clone()),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Call { f, arguments } => reduce_call_expression(f, arguments, symbol_table),
|
Call { f, arguments } => reduce_call_expression(f, arguments, symbol_table),
|
||||||
TupleLiteral(exprs) => Expr::Tuple(exprs.iter().map(|e| e.node().reduce(symbol_table)).collect()),
|
TupleLiteral(exprs) => Expr::Tuple(exprs.iter().map(|e| e.node().reduce(symbol_table)).collect()),
|
||||||
@ -183,8 +203,12 @@ fn reduce_lambda(params: &Vec<FormalParam>, body: &Block, symbol_table: &SymbolT
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_named_struct(name: &Rc<String>, fields: &Vec<(Rc<String>, Meta<Expression>)>, symbol_table: &SymbolTable) -> Expr {
|
fn reduce_named_struct(name: &QualifiedName, fields: &Vec<(Rc<String>, Meta<Expression>)>, symbol_table: &SymbolTable) -> Expr {
|
||||||
let (type_name, index, members_from_table) = match symbol_table.lookup_by_name(name) {
|
|
||||||
|
let sym_name = lookup_name_in_scope(name);
|
||||||
|
let FullyQualifiedSymbolName(ref v) = sym_name;
|
||||||
|
let ref name = v.last().unwrap().name;
|
||||||
|
let (type_name, index, members_from_table) = match symbol_table.lookup_by_fqsn(&sym_name) {
|
||||||
Some(Symbol { spec: SymbolSpec::RecordConstructor { members, type_name, index }, .. }) => (type_name.clone(), index, members),
|
Some(Symbol { spec: SymbolSpec::RecordConstructor { members, type_name, index }, .. }) => (type_name.clone(), index, members),
|
||||||
_ => return Expr::ReductionError("Not a record constructor".to_string()),
|
_ => return Expr::ReductionError("Not a record constructor".to_string()),
|
||||||
};
|
};
|
||||||
|
@ -26,8 +26,8 @@ impl fmt::Display for FullyQualifiedSymbolName {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct ScopeSegment {
|
pub struct ScopeSegment {
|
||||||
name: Rc<String>, //TODO maybe this could be a &str, for efficiency?
|
pub name: Rc<String>, //TODO maybe this could be a &str, for efficiency?
|
||||||
kind: ScopeSegmentKind,
|
pub kind: ScopeSegmentKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ScopeSegment {
|
impl fmt::Display for ScopeSegment {
|
||||||
|
@ -412,10 +412,12 @@ impl<'a> TypeContext<'a> {
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_value(&mut self, val: &Rc<String>) -> InferResult<Type> {
|
fn handle_value(&mut self, val: &QualifiedName) -> InferResult<Type> {
|
||||||
match self.variable_map.lookup(val) {
|
let QualifiedName(vec) = val;
|
||||||
|
let var = &vec[0];
|
||||||
|
match self.variable_map.lookup(var) {
|
||||||
Some(ty) => Ok(ty.clone()),
|
Some(ty) => Ok(ty.clone()),
|
||||||
None => TypeError::new(format!("Couldn't find variable: {}", val))
|
None => TypeError::new(format!("Couldn't find variable: {}", &var)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user