Start work on qualified names

This commit is contained in:
greg 2019-08-31 23:39:01 -07:00
parent 89d967aee4
commit 34abb9b081
6 changed files with 73 additions and 27 deletions

View File

@ -46,6 +46,9 @@ pub enum Statement {
pub type Block = Vec<Meta<Statement>>;
pub type ParamName = Rc<String>;
#[derive(Debug, PartialEq, Clone)]
pub struct QualifiedName(pub Vec<Rc<String>>);
#[derive(Debug, PartialEq, Clone)]
pub struct FormalParam {
pub name: ParamName,
@ -138,9 +141,9 @@ pub enum ExpressionKind {
BinExp(BinOp, Box<Meta<Expression>>, Box<Meta<Expression>>),
PrefixExp(PrefixOp, Box<Meta<Expression>>),
TupleLiteral(Vec<Meta<Expression>>),
Value(Rc<String>),
Value(QualifiedName),
NamedStruct {
name: Rc<String>,
name: QualifiedName,
fields: Vec<(Rc<String>, Meta<Expression>)>,
},
Call {

View File

@ -85,13 +85,14 @@
//! lambda_param_list := formal_param_list | formal_param
//! paren_expr := "(" paren_inner ")"
//! paren_inner := (expression ",")*
//! identifier_expr := named_struct | IDENTIFIER
//! identifier_expr := qualified_identifier | named_struct
//! qualified_identifier := IDENTIFIER ("::" IDENTIFIER)*
//! ```
//!
//! ## Literals
//! ```text
//! 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_entry := IDENTIFIER ":" expression
//! anonymous_struct := TODO
@ -213,6 +214,7 @@ impl TokenHandler {
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})
}
/// calling peek_n(0) is the same thing as peek()
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})
}
@ -757,16 +759,31 @@ impl Parser {
#[recursive_descent_method]
fn identifier_expr(&mut self) -> ParseResult<Expression> {
use self::ExpressionKind::*;
let identifier = self.identifier()?;
let qualified_identifier = self.qualified_identifier()?;
Ok(match self.token_handler.peek_kind() {
LCurlyBrace if !self.restrictions.no_struct_literal => {
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]
fn record_block(&mut self) -> ParseResult<Vec<(Rc<String>, Meta<Expression>)>> {
Ok(

View File

@ -4,7 +4,7 @@ use std::str::FromStr;
use super::tokenize;
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::Declaration::*;
use super::Signature;
@ -30,7 +30,7 @@ macro_rules! parse_error {
($string:expr) => { assert!(parse($string).is_err()) }
}
macro_rules! val {
($var:expr) => { Value(Rc::new($var.to_string())) }
($var:expr) => { Value(QualifiedName(vec![Rc::new($var.to_string())])) };
}
macro_rules! ty {
($name:expr) => { Singleton(tys!($name)) }
@ -153,11 +153,11 @@ fn parsing_identifiers() {
parse_test!("None", AST(vec![exst!(val!("None"))]));
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, }",
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")))]
}
)

View File

@ -16,7 +16,7 @@ use std::rc::Rc;
use std::str::FromStr;
use crate::ast::*;
use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable};
use crate::symbol_table::{Symbol, SymbolSpec, SymbolTable, ScopeSegment, ScopeSegmentKind, FullyQualifiedSymbolName};
use crate::builtin::Builtin;
#[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 {
fn reduce(&self, symbol_table: &SymbolTable) -> Expr {
use crate::ast::ExpressionKind::*;
@ -153,14 +168,19 @@ impl Expression {
BoolLiteral(b) => Expr::Lit(Lit::Bool(*b)),
BinExp(binop, lhs, rhs) => binop.reduce(symbol_table, lhs, rhs),
PrefixExp(op, arg) => op.reduce(symbol_table, arg),
Value(name) => match symbol_table.lookup_by_name(name) {
Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
type_name: type_name.clone(),
name: name.clone(),
tag: index.clone(),
arity: type_args.len(),
},
_ => Expr::Sym(name.clone()),
Value(qualified_name) => {
let sym_name = lookup_name_in_scope(&qualified_name);
let FullyQualifiedSymbolName(ref v) = sym_name;
let name = v.last().unwrap().name.clone();
match symbol_table.lookup_by_fqsn(&sym_name) {
Some(Symbol { spec: SymbolSpec::DataConstructor { index, type_args, type_name}, .. }) => Expr::Constructor {
type_name: type_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),
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 {
let (type_name, index, members_from_table) = match symbol_table.lookup_by_name(name) {
fn reduce_named_struct(name: &QualifiedName, fields: &Vec<(Rc<String>, Meta<Expression>)>, symbol_table: &SymbolTable) -> Expr {
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),
_ => return Expr::ReductionError("Not a record constructor".to_string()),
};

View File

@ -26,8 +26,8 @@ impl fmt::Display for FullyQualifiedSymbolName {
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ScopeSegment {
name: Rc<String>, //TODO maybe this could be a &str, for efficiency?
kind: ScopeSegmentKind,
pub name: Rc<String>, //TODO maybe this could be a &str, for efficiency?
pub kind: ScopeSegmentKind,
}
impl fmt::Display for ScopeSegment {

View File

@ -412,10 +412,12 @@ impl<'a> TypeContext<'a> {
Ok(output)
}
fn handle_value(&mut self, val: &Rc<String>) -> InferResult<Type> {
match self.variable_map.lookup(val) {
fn handle_value(&mut self, val: &QualifiedName) -> InferResult<Type> {
let QualifiedName(vec) = val;
let var = &vec[0];
match self.variable_map.lookup(var) {
Some(ty) => Ok(ty.clone()),
None => TypeError::new(format!("Couldn't find variable: {}", val))
None => TypeError::new(format!("Couldn't find variable: {}", &var)),
}
}