Work
This commit is contained in:
parent
c5eed8dcf8
commit
fabb66148d
|
@ -1,3 +1,4 @@
|
|||
#![feature(let_chains)]
|
||||
mod err;
|
||||
mod ir;
|
||||
mod lookahead;
|
||||
|
@ -58,7 +59,7 @@ fn test_expression(expr: &str) {
|
|||
let source = expr.to_string();
|
||||
let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful());
|
||||
let mut parser = Parser::new(tokens);
|
||||
println!("{:?}", parser.expression(0).unwrap());
|
||||
println!("{:#?}", parser.expression(0).unwrap());
|
||||
}
|
||||
|
||||
fn tokenize(input: &'static str) -> impl Iterator<Item = Token> {
|
||||
|
@ -78,7 +79,6 @@ fn main() -> Result<()> {
|
|||
*/
|
||||
//let module = frontend::Module::from_file("./demo.hal")?;
|
||||
//module.write_to("test");
|
||||
let p = punycode::encode("-_").unwrap();
|
||||
println!("{p}");
|
||||
test_expression("asdf~+ + 3");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -105,27 +105,27 @@ impl std::fmt::Display for ExpressionKind {
|
|||
right,
|
||||
} => {
|
||||
write!(f, "({left} {token} {right})")
|
||||
}
|
||||
},
|
||||
e::Parenthesis(inner) => write!(f, "{inner}"),
|
||||
e::Unary { op: token, child } => {
|
||||
write!(f, "({token} {child})")
|
||||
}
|
||||
},
|
||||
e::Identifier { name, .. } => write!(f, "{name}"),
|
||||
e::FunctionCall { callee, args, .. } => {
|
||||
write!(f, "({callee} call {args:?})")
|
||||
}
|
||||
},
|
||||
e::Field {
|
||||
namespace, field, ..
|
||||
} => {
|
||||
write!(f, "({namespace} . {field})")
|
||||
}
|
||||
},
|
||||
e::FunctionDef {
|
||||
params,
|
||||
returns_str,
|
||||
..
|
||||
} => {
|
||||
write!(f, "(fn({params:?}) -> {returns_str:?})")
|
||||
}
|
||||
},
|
||||
e::StructDef(params) => write!(f, "struct {{ {params:?} }}"),
|
||||
e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"),
|
||||
e::Block(block) => {
|
||||
|
@ -134,7 +134,7 @@ impl std::fmt::Display for ExpressionKind {
|
|||
write!(f, "{:#?}", s)?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
},
|
||||
e::If { block, else_, .. } => {
|
||||
write!(f, "{{\n")?;
|
||||
for s in block {
|
||||
|
@ -145,7 +145,7 @@ impl std::fmt::Display for ExpressionKind {
|
|||
write!(f, "{else_}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,13 +163,13 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
let next = self.peek(0)?;
|
||||
// Unary prefix expression
|
||||
let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) {
|
||||
self.skip(1);
|
||||
let span = next.1;
|
||||
if operator.assoc() == RIGHT_ASSOC {
|
||||
return error()
|
||||
.reason(format!("The {} operator must come after a value", operator))
|
||||
.span(&span);
|
||||
}
|
||||
self.skip(1);
|
||||
let child = self
|
||||
.expression(operator.precedence())
|
||||
.trace(format!("while parsing unary {}", operator))
|
||||
|
@ -190,29 +190,62 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
|
||||
// Precedence climbing loop
|
||||
while let Ok(next) = self.peek(0) {
|
||||
// Binary infix
|
||||
// Binary or mixed
|
||||
if let Ok(operator) = BinaryOp::try_from(&next.0) {
|
||||
let new_precedence = operator.precedence();
|
||||
if ((operator.assoc() == LEFT_ASSOC) && new_precedence <= precedence)
|
||||
|| (new_precedence < precedence)
|
||||
{
|
||||
return Ok(current);
|
||||
'binop: {
|
||||
// Operator may be postfix unary
|
||||
if let Ok(operator) = UnaryOp::try_from(&next.0)
|
||||
&& operator.assoc() == RIGHT_ASSOC
|
||||
{
|
||||
let is_unop = if let Err(_) = self.peek(1) {
|
||||
true // Reached past end of input, must be unop
|
||||
} else if let Ok(Token(t::EOF, _)) = self.peek(1) {
|
||||
true // Reached end of input, must be unop
|
||||
} else if let Ok(next2) = self.peek(1)
|
||||
&& (BinaryOp::try_from(&next2.0).is_ok()
|
||||
|| UnaryOp::try_from(&next2.0)
|
||||
.is_ok_and(|u| u.assoc() == RIGHT_ASSOC))
|
||||
{
|
||||
true // Next is op
|
||||
} else {
|
||||
false
|
||||
};
|
||||
// Op is postfix unary
|
||||
if is_unop {
|
||||
let span = next.1;
|
||||
self.skip(1);
|
||||
current = Expression::new(
|
||||
e::Unary {
|
||||
op: operator,
|
||||
child: current.into(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
break 'binop;
|
||||
}
|
||||
}
|
||||
let new_precedence = operator.precedence();
|
||||
if ((operator.assoc() == LEFT_ASSOC) && new_precedence <= precedence)
|
||||
|| (new_precedence < precedence)
|
||||
{
|
||||
return Ok(current);
|
||||
}
|
||||
self.skip(1);
|
||||
let span = next.1;
|
||||
let rhs = self
|
||||
.expression(new_precedence)
|
||||
.trace(format!("while parsing binary {}", operator))
|
||||
.span(&span)?;
|
||||
let span = next.1 + rhs.span;
|
||||
current = Expression::new(
|
||||
e::Binary {
|
||||
op: operator,
|
||||
left: current.into(),
|
||||
right: rhs.into(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
self.skip(1);
|
||||
let span = next.1;
|
||||
let rhs = self
|
||||
.expression(new_precedence)
|
||||
.trace(format!("while parsing binary {}", operator))
|
||||
.span(&span)?;
|
||||
let span = next.1 + rhs.span;
|
||||
current = Expression::new(
|
||||
e::Binary {
|
||||
op: operator,
|
||||
left: current.into(),
|
||||
right: rhs.into(),
|
||||
},
|
||||
span,
|
||||
);
|
||||
}
|
||||
// Field
|
||||
else if let Token(t::Dot, span) = next {
|
||||
|
@ -243,7 +276,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
Ok(a) => {
|
||||
span = span + a.span;
|
||||
args.push(a)
|
||||
}
|
||||
},
|
||||
Err(_) => break,
|
||||
};
|
||||
if !self.eat(t::Comma).is_ok() {
|
||||
|
@ -263,7 +296,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
else if let Ok(operator) = UnaryOp::try_from(&next.0) {
|
||||
self.skip(1);
|
||||
let span = next.1;
|
||||
if operator.assoc() == RIGHT_ASSOC {
|
||||
if operator.assoc() == LEFT_ASSOC {
|
||||
return error()
|
||||
.reason(format!(
|
||||
"The {} operator must come before a value",
|
||||
|
@ -302,9 +335,10 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
names.push(name.clone());
|
||||
// Param type (optional)
|
||||
if self.eat(t::Colon).is_ok() {
|
||||
let (type_name, span2) = self
|
||||
.identifier()
|
||||
.trace_span(span + span2, format!("While parsing type of '{}'", name))?;
|
||||
let (type_name, span2) = self.identifier().trace_span(
|
||||
span + span2,
|
||||
format!("While parsing type of '{}'", name),
|
||||
)?;
|
||||
strongly_typed = true;
|
||||
span = span + span2;
|
||||
type_names.push(type_name);
|
||||
|
@ -358,37 +392,38 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
t::IntegerLiteral(i, b) => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::Integer(i, b))
|
||||
}
|
||||
},
|
||||
t::FloatLiteral(f) => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::Real(f))
|
||||
}
|
||||
},
|
||||
t::StringLiteral(s) => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::String(s))
|
||||
}
|
||||
},
|
||||
t::GlyphLiteral(c) => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::Glyph(c))
|
||||
}
|
||||
},
|
||||
t::True => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::Boolean(true))
|
||||
}
|
||||
},
|
||||
t::False => {
|
||||
self.skip(1);
|
||||
e::Immediate(im::Boolean(false))
|
||||
}
|
||||
},
|
||||
t::If => return self.if_else(),
|
||||
t::LeftBrace => {
|
||||
let (block, span1) = self.block()?;
|
||||
span = span + span1;
|
||||
e::Block(block)
|
||||
}
|
||||
},
|
||||
// Function definition
|
||||
t::LeftParen
|
||||
if (self.look(1, t::Identifier("".into())).is_ok()
|
||||
&& (self.look(2, t::Colon).is_ok() || self.look(2, t::Comma).is_ok()))
|
||||
&& (self.look(2, t::Colon).is_ok()
|
||||
|| self.look(2, t::Comma).is_ok()))
|
||||
|| self.look(1, t::RightParen).is_ok() =>
|
||||
{
|
||||
self.skip(1);
|
||||
|
@ -417,7 +452,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
returns_str,
|
||||
body,
|
||||
}
|
||||
}
|
||||
},
|
||||
// Struct definition
|
||||
t::Struct => {
|
||||
self.skip(1);
|
||||
|
@ -425,7 +460,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
let params = self.parameters(span)?;
|
||||
self.eat(t::RightBrace)?;
|
||||
e::StructDef(params)
|
||||
}
|
||||
},
|
||||
// Struct literal
|
||||
t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => {
|
||||
self.skip(2);
|
||||
|
@ -450,11 +485,11 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
}
|
||||
self.eat(t::RightBrace)?;
|
||||
e::StructLiteral { name, args }
|
||||
}
|
||||
},
|
||||
t::Identifier(i) => {
|
||||
self.skip(1);
|
||||
e::Identifier { name: i }
|
||||
}
|
||||
},
|
||||
// Parenthetical
|
||||
t::LeftParen => {
|
||||
self.skip(1);
|
||||
|
@ -466,12 +501,12 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
.reason("Unclosed '('")
|
||||
.span(&expr.span)?;
|
||||
e::Parenthesis(expr.into())
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return error()
|
||||
.span(&span)
|
||||
.reason(format!("Expected expression, found {}", next.0));
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(Expression::new(kind, span))
|
||||
}
|
||||
|
@ -512,7 +547,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
|
|||
Ok(Token(t::Identifier(i), span)) => {
|
||||
self.skip(1);
|
||||
Ok((i, span))
|
||||
}
|
||||
},
|
||||
Ok(t) => error()
|
||||
.reason(format!("Expected identifier, found {}", t.0))
|
||||
.span(&t.1),
|
||||
|
|
|
@ -74,13 +74,16 @@ op! {
|
|||
|
||||
op! {
|
||||
UnaryOp;
|
||||
Bang, 12, RIGHT_ASSOC;
|
||||
Question, 12, RIGHT_ASSOC;
|
||||
Plus, 11, RIGHT_ASSOC;
|
||||
Tilda, 11, RIGHT_ASSOC;
|
||||
Minus, 11, LEFT_ASSOC;
|
||||
Plus, 11, LEFT_ASSOC;
|
||||
Not, 11, LEFT_ASSOC;
|
||||
}
|
||||
|
||||
pub fn is_mixed_op(t: &TokenKind) -> bool {
|
||||
BinaryOp::try_from(t).is_ok() && UnaryOp::try_from(t).is_ok()
|
||||
}
|
||||
|
||||
const FIELD_PREC: Precedence = 13;
|
||||
const CALL_PREC: Precedence = 12;
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::{err::*, Expression, ExpressionKind, Statement, StatementKind};
|
||||
use crate::{
|
||||
Expression, ExpressionKind, Span, Statement, StatementKind, err::*,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use ir::*;
|
||||
|
@ -9,8 +11,7 @@ use ir::*;
|
|||
enum Undo {
|
||||
FuncGuard,
|
||||
BlockGuard,
|
||||
Symbol { name: String, prev: Vec<Symbol> },
|
||||
Push { name: String },
|
||||
Symbol { name: String, prev: Symbol },
|
||||
None,
|
||||
}
|
||||
|
||||
|
@ -23,28 +24,49 @@ struct Symbol {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
struct SymbolTable {
|
||||
types: HashMap<TID, Type>,
|
||||
table: HashMap<String, Vec<Symbol>>,
|
||||
type_table: Vec<Type>,
|
||||
sym_table: HashMap<String, Symbol>,
|
||||
undo_stack: Vec<Undo>,
|
||||
path: Vec<String>,
|
||||
salt: usize,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl SymbolTable {
|
||||
fn define(&mut self, name: &str, type_: TID, life: Lifetime) {
|
||||
if !self.table.contains_key(name) {
|
||||
self.table.insert(name.to_string(), vec![]);
|
||||
}
|
||||
let symbols = self.table.get_mut(name).unwrap();
|
||||
fn define_symbol(&mut self, name: &str, type_: TID) {
|
||||
let mut path = self.path.clone();
|
||||
path.push(name.to_string());
|
||||
let mangle = names::mangle(path, &format!("{:#x}", self.salt));
|
||||
let undo = match self.sym_table.get(name) {
|
||||
Some(prev) => Undo::Symbol {
|
||||
name: name.to_string(),
|
||||
prev: prev.clone(),
|
||||
},
|
||||
None => Undo::None,
|
||||
};
|
||||
self.undo_stack.push(undo);
|
||||
let mangle = names::mangle(path, &self.salt.to_string());
|
||||
let symbol = Symbol {
|
||||
mangle,
|
||||
type_,
|
||||
life,
|
||||
life: if self.depth == 0 {
|
||||
Lifetime::Static
|
||||
} else {
|
||||
Lifetime::Dynamic
|
||||
},
|
||||
};
|
||||
let undo = if
|
||||
self.sym_table.insert(name.to_string(), symbol);
|
||||
}
|
||||
|
||||
fn query_symbol(&mut self, name: &str) -> Result<&Symbol> {
|
||||
self.sym_table.get(name).ok_or(Diagnostic::new(
|
||||
format!("The name {name} is not declared in this scope",),
|
||||
None,
|
||||
))
|
||||
}
|
||||
|
||||
fn define_type(&mut self, type_: Type) -> TID {
|
||||
self.type_table.push(type_);
|
||||
self.type_table.len()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ pub enum TokenKind {
|
|||
Slash,
|
||||
Star,
|
||||
Percent,
|
||||
Tilda,
|
||||
Arrow,
|
||||
FatArrow,
|
||||
PlusEqual,
|
||||
|
@ -278,6 +279,7 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
|
|||
'&' => Ampersand,
|
||||
'^' => Carrot,
|
||||
'#' => Hash,
|
||||
'~' => Tilda,
|
||||
'.' if not_next('.') => Dot,
|
||||
'+' if not_next('=') => Plus,
|
||||
'-' if not_next('=') && not_next('>') => Minus,
|
||||
|
|
Loading…
Reference in a new issue