This commit is contained in:
Logan 2024-12-22 05:49:49 -06:00
parent c5eed8dcf8
commit fabb66148d
5 changed files with 130 additions and 68 deletions

View file

@ -1,3 +1,4 @@
#![feature(let_chains)]
mod err; mod err;
mod ir; mod ir;
mod lookahead; mod lookahead;
@ -58,7 +59,7 @@ fn test_expression(expr: &str) {
let source = expr.to_string(); let source = expr.to_string();
let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful()); let tokens = Tokenizer::new(source.chars()).filter(|t| t.0.is_meaningful());
let mut parser = Parser::new(tokens); 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> { fn tokenize(input: &'static str) -> impl Iterator<Item = Token> {
@ -78,7 +79,6 @@ fn main() -> Result<()> {
*/ */
//let module = frontend::Module::from_file("./demo.hal")?; //let module = frontend::Module::from_file("./demo.hal")?;
//module.write_to("test"); //module.write_to("test");
let p = punycode::encode("-_").unwrap(); test_expression("asdf~+ + 3");
println!("{p}");
Ok(()) Ok(())
} }

View file

@ -105,27 +105,27 @@ impl std::fmt::Display for ExpressionKind {
right, right,
} => { } => {
write!(f, "({left} {token} {right})") write!(f, "({left} {token} {right})")
} },
e::Parenthesis(inner) => write!(f, "{inner}"), e::Parenthesis(inner) => write!(f, "{inner}"),
e::Unary { op: token, child } => { e::Unary { op: token, child } => {
write!(f, "({token} {child})") write!(f, "({token} {child})")
} },
e::Identifier { name, .. } => write!(f, "{name}"), e::Identifier { name, .. } => write!(f, "{name}"),
e::FunctionCall { callee, args, .. } => { e::FunctionCall { callee, args, .. } => {
write!(f, "({callee} call {args:?})") write!(f, "({callee} call {args:?})")
} },
e::Field { e::Field {
namespace, field, .. namespace, field, ..
} => { } => {
write!(f, "({namespace} . {field})") write!(f, "({namespace} . {field})")
} },
e::FunctionDef { e::FunctionDef {
params, params,
returns_str, returns_str,
.. ..
} => { } => {
write!(f, "(fn({params:?}) -> {returns_str:?})") write!(f, "(fn({params:?}) -> {returns_str:?})")
} },
e::StructDef(params) => write!(f, "struct {{ {params:?} }}"), e::StructDef(params) => write!(f, "struct {{ {params:?} }}"),
e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"), e::StructLiteral { name, args, .. } => write!(f, "{name} {{ {args:?} }}"),
e::Block(block) => { e::Block(block) => {
@ -134,7 +134,7 @@ impl std::fmt::Display for ExpressionKind {
write!(f, "{:#?}", s)?; write!(f, "{:#?}", s)?;
} }
write!(f, "}}") write!(f, "}}")
} },
e::If { block, else_, .. } => { e::If { block, else_, .. } => {
write!(f, "{{\n")?; write!(f, "{{\n")?;
for s in block { for s in block {
@ -145,7 +145,7 @@ impl std::fmt::Display for ExpressionKind {
write!(f, "{else_}")?; write!(f, "{else_}")?;
} }
Ok(()) Ok(())
} },
} }
} }
} }
@ -163,13 +163,13 @@ impl<I: Iterator<Item = Token>> Parser<I> {
let next = self.peek(0)?; let next = self.peek(0)?;
// Unary prefix expression // Unary prefix expression
let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) { let mut current = if let Ok(operator) = UnaryOp::try_from(&next.0) {
self.skip(1);
let span = next.1; let span = next.1;
if operator.assoc() == RIGHT_ASSOC { if operator.assoc() == RIGHT_ASSOC {
return error() return error()
.reason(format!("The {} operator must come after a value", operator)) .reason(format!("The {} operator must come after a value", operator))
.span(&span); .span(&span);
} }
self.skip(1);
let child = self let child = self
.expression(operator.precedence()) .expression(operator.precedence())
.trace(format!("while parsing unary {}", operator)) .trace(format!("while parsing unary {}", operator))
@ -190,29 +190,62 @@ impl<I: Iterator<Item = Token>> Parser<I> {
// Precedence climbing loop // Precedence climbing loop
while let Ok(next) = self.peek(0) { while let Ok(next) = self.peek(0) {
// Binary infix // Binary or mixed
if let Ok(operator) = BinaryOp::try_from(&next.0) { if let Ok(operator) = BinaryOp::try_from(&next.0) {
let new_precedence = operator.precedence(); 'binop: {
if ((operator.assoc() == LEFT_ASSOC) && new_precedence <= precedence) // Operator may be postfix unary
|| (new_precedence < precedence) if let Ok(operator) = UnaryOp::try_from(&next.0)
{ && operator.assoc() == RIGHT_ASSOC
return Ok(current); {
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 // Field
else if let Token(t::Dot, span) = next { else if let Token(t::Dot, span) = next {
@ -243,7 +276,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(a) => { Ok(a) => {
span = span + a.span; span = span + a.span;
args.push(a) args.push(a)
} },
Err(_) => break, Err(_) => break,
}; };
if !self.eat(t::Comma).is_ok() { 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) { else if let Ok(operator) = UnaryOp::try_from(&next.0) {
self.skip(1); self.skip(1);
let span = next.1; let span = next.1;
if operator.assoc() == RIGHT_ASSOC { if operator.assoc() == LEFT_ASSOC {
return error() return error()
.reason(format!( .reason(format!(
"The {} operator must come before a value", "The {} operator must come before a value",
@ -302,9 +335,10 @@ impl<I: Iterator<Item = Token>> Parser<I> {
names.push(name.clone()); names.push(name.clone());
// Param type (optional) // Param type (optional)
if self.eat(t::Colon).is_ok() { if self.eat(t::Colon).is_ok() {
let (type_name, span2) = self let (type_name, span2) = self.identifier().trace_span(
.identifier() span + span2,
.trace_span(span + span2, format!("While parsing type of '{}'", name))?; format!("While parsing type of '{}'", name),
)?;
strongly_typed = true; strongly_typed = true;
span = span + span2; span = span + span2;
type_names.push(type_name); type_names.push(type_name);
@ -358,37 +392,38 @@ impl<I: Iterator<Item = Token>> Parser<I> {
t::IntegerLiteral(i, b) => { t::IntegerLiteral(i, b) => {
self.skip(1); self.skip(1);
e::Immediate(im::Integer(i, b)) e::Immediate(im::Integer(i, b))
} },
t::FloatLiteral(f) => { t::FloatLiteral(f) => {
self.skip(1); self.skip(1);
e::Immediate(im::Real(f)) e::Immediate(im::Real(f))
} },
t::StringLiteral(s) => { t::StringLiteral(s) => {
self.skip(1); self.skip(1);
e::Immediate(im::String(s)) e::Immediate(im::String(s))
} },
t::GlyphLiteral(c) => { t::GlyphLiteral(c) => {
self.skip(1); self.skip(1);
e::Immediate(im::Glyph(c)) e::Immediate(im::Glyph(c))
} },
t::True => { t::True => {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(true)) e::Immediate(im::Boolean(true))
} },
t::False => { t::False => {
self.skip(1); self.skip(1);
e::Immediate(im::Boolean(false)) e::Immediate(im::Boolean(false))
} },
t::If => return self.if_else(), t::If => return self.if_else(),
t::LeftBrace => { t::LeftBrace => {
let (block, span1) = self.block()?; let (block, span1) = self.block()?;
span = span + span1; span = span + span1;
e::Block(block) e::Block(block)
} },
// Function definition // Function definition
t::LeftParen t::LeftParen
if (self.look(1, t::Identifier("".into())).is_ok() 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.look(1, t::RightParen).is_ok() =>
{ {
self.skip(1); self.skip(1);
@ -417,7 +452,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
returns_str, returns_str,
body, body,
} }
} },
// Struct definition // Struct definition
t::Struct => { t::Struct => {
self.skip(1); self.skip(1);
@ -425,7 +460,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
let params = self.parameters(span)?; let params = self.parameters(span)?;
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructDef(params) e::StructDef(params)
} },
// Struct literal // Struct literal
t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => { t::Identifier(name) if self.look(1, t::LeftBrace).is_ok() => {
self.skip(2); self.skip(2);
@ -450,11 +485,11 @@ impl<I: Iterator<Item = Token>> Parser<I> {
} }
self.eat(t::RightBrace)?; self.eat(t::RightBrace)?;
e::StructLiteral { name, args } e::StructLiteral { name, args }
} },
t::Identifier(i) => { t::Identifier(i) => {
self.skip(1); self.skip(1);
e::Identifier { name: i } e::Identifier { name: i }
} },
// Parenthetical // Parenthetical
t::LeftParen => { t::LeftParen => {
self.skip(1); self.skip(1);
@ -466,12 +501,12 @@ impl<I: Iterator<Item = Token>> Parser<I> {
.reason("Unclosed '('") .reason("Unclosed '('")
.span(&expr.span)?; .span(&expr.span)?;
e::Parenthesis(expr.into()) e::Parenthesis(expr.into())
} },
_ => { _ => {
return error() return error()
.span(&span) .span(&span)
.reason(format!("Expected expression, found {}", next.0)); .reason(format!("Expected expression, found {}", next.0));
} },
}; };
Ok(Expression::new(kind, span)) Ok(Expression::new(kind, span))
} }
@ -512,7 +547,7 @@ impl<I: Iterator<Item = Token>> Parser<I> {
Ok(Token(t::Identifier(i), span)) => { Ok(Token(t::Identifier(i), span)) => {
self.skip(1); self.skip(1);
Ok((i, span)) Ok((i, span))
} },
Ok(t) => error() Ok(t) => error()
.reason(format!("Expected identifier, found {}", t.0)) .reason(format!("Expected identifier, found {}", t.0))
.span(&t.1), .span(&t.1),

View file

@ -74,13 +74,16 @@ op! {
op! { op! {
UnaryOp; UnaryOp;
Bang, 12, RIGHT_ASSOC; Plus, 11, RIGHT_ASSOC;
Question, 12, RIGHT_ASSOC; Tilda, 11, RIGHT_ASSOC;
Minus, 11, LEFT_ASSOC; Minus, 11, LEFT_ASSOC;
Plus, 11, LEFT_ASSOC;
Not, 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 FIELD_PREC: Precedence = 13;
const CALL_PREC: Precedence = 12; const CALL_PREC: Precedence = 12;

View file

@ -1,6 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use crate::{err::*, Expression, ExpressionKind, Statement, StatementKind}; use crate::{
Expression, ExpressionKind, Span, Statement, StatementKind, err::*,
};
use super::*; use super::*;
use ir::*; use ir::*;
@ -9,8 +11,7 @@ use ir::*;
enum Undo { enum Undo {
FuncGuard, FuncGuard,
BlockGuard, BlockGuard,
Symbol { name: String, prev: Vec<Symbol> }, Symbol { name: String, prev: Symbol },
Push { name: String },
None, None,
} }
@ -23,28 +24,49 @@ struct Symbol {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct SymbolTable { struct SymbolTable {
types: HashMap<TID, Type>, type_table: Vec<Type>,
table: HashMap<String, Vec<Symbol>>, sym_table: HashMap<String, Symbol>,
undo_stack: Vec<Undo>, undo_stack: Vec<Undo>,
path: Vec<String>, path: Vec<String>,
salt: usize, salt: usize,
depth: usize,
} }
impl SymbolTable { impl SymbolTable {
fn define(&mut self, name: &str, type_: TID, life: Lifetime) { fn define_symbol(&mut self, name: &str, type_: TID) {
if !self.table.contains_key(name) {
self.table.insert(name.to_string(), vec![]);
}
let symbols = self.table.get_mut(name).unwrap();
let mut path = self.path.clone(); let mut path = self.path.clone();
path.push(name.to_string()); 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 { let symbol = Symbol {
mangle, mangle,
type_, 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()
} }
} }

View file

@ -30,6 +30,7 @@ pub enum TokenKind {
Slash, Slash,
Star, Star,
Percent, Percent,
Tilda,
Arrow, Arrow,
FatArrow, FatArrow,
PlusEqual, PlusEqual,
@ -278,6 +279,7 @@ impl<I: Iterator<Item = char>> Tokenizer<I> {
'&' => Ampersand, '&' => Ampersand,
'^' => Carrot, '^' => Carrot,
'#' => Hash, '#' => Hash,
'~' => Tilda,
'.' if not_next('.') => Dot, '.' if not_next('.') => Dot,
'+' if not_next('=') => Plus, '+' if not_next('=') => Plus,
'-' if not_next('=') && not_next('>') => Minus, '-' if not_next('=') && not_next('>') => Minus,