feat: Implement lexer and parser for AST
Introduces the lexer and parser modules, enabling the conversion of source code into an Abstract Syntax Tree (AST). This includes: - Defining token kinds and structures. - Implementing lexer logic to tokenize input. - Defining AST node kinds and structures. - Implementing parser logic to construct the AST from tokens. - Adding support for basic expressions, lists, keywords, and identifiers. - Adding the `lazy_static` dependency for keyword interning. - Refactoring `Value::Nil` to `Value::Void`.
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
use std::sync::Arc;
|
||||
use crate::ast::lexer::{Lexer, Token, TokenKind};
|
||||
use crate::ast::types::{Identity, NodeIdentity, Value, Keyword};
|
||||
use crate::ast::nodes::{Node, UntypedKind};
|
||||
|
||||
pub struct Parser<'a> {
|
||||
lexer: Lexer<'a>,
|
||||
current_token: Token,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn new(input: &'a str) -> Result<Self, String> {
|
||||
let mut lexer = Lexer::new(input);
|
||||
let current_token = lexer.next_token()?;
|
||||
Ok(Self { lexer, current_token })
|
||||
}
|
||||
|
||||
fn advance(&mut self) -> Result<Token, String> {
|
||||
let prev = std::mem::replace(&mut self.current_token, self.lexer.next_token()?);
|
||||
Ok(prev)
|
||||
}
|
||||
|
||||
fn peek(&self) -> &TokenKind {
|
||||
&self.current_token.kind
|
||||
}
|
||||
|
||||
pub fn parse_expression(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
match self.peek() {
|
||||
TokenKind::LeftParen => self.parse_list(),
|
||||
TokenKind::LeftBracket => self.parse_vector(),
|
||||
// TokenKind::LeftBrace => self.parse_map(), // TODO
|
||||
TokenKind::Quote => {
|
||||
let identity = Arc::new(NodeIdentity { location: self.current_token.location });
|
||||
self.parse_reader_macro(UntypedKind::Call {
|
||||
callee: Box::new(self.make_id_node("quote", identity)),
|
||||
args: vec![], // will be filled
|
||||
})
|
||||
}
|
||||
_ => self.parse_atom(),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_atom(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?;
|
||||
let identity = Arc::new(NodeIdentity { location: token.location });
|
||||
|
||||
let kind = match token.kind {
|
||||
TokenKind::Number(n) => UntypedKind::Constant(Value::Float(n)),
|
||||
TokenKind::String(s) => UntypedKind::Constant(Value::Text(s)),
|
||||
TokenKind::Keyword(k) => UntypedKind::Constant(Value::Keyword(Keyword::intern(&k))),
|
||||
TokenKind::Identifier(id) => {
|
||||
match id.as_ref() {
|
||||
"..." => UntypedKind::Nop,
|
||||
"true" => UntypedKind::Constant(Value::Bool(true)),
|
||||
"false" => UntypedKind::Constant(Value::Bool(false)),
|
||||
"void" => UntypedKind::Constant(Value::Void),
|
||||
_ => UntypedKind::Identifier(id),
|
||||
}
|
||||
}
|
||||
_ => return Err(format!("Unexpected token in atom: {:?} at {:?}", token.kind, token.location)),
|
||||
};
|
||||
|
||||
Ok(Node { identity, kind })
|
||||
}
|
||||
|
||||
fn parse_list(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let start_loc = self.advance()?.location; // consume '('
|
||||
|
||||
if *self.peek() == TokenKind::RightParen {
|
||||
return Err(format!("Empty list () is not a valid expression at {:?}", start_loc));
|
||||
}
|
||||
|
||||
// Peek at head to check for special forms
|
||||
let head = self.parse_expression()?;
|
||||
|
||||
let result = if let UntypedKind::Identifier(name) = &head.kind {
|
||||
match name.as_ref() {
|
||||
"if" => self.parse_if(head.identity.clone()),
|
||||
_ => self.parse_call(head),
|
||||
}
|
||||
} else {
|
||||
self.parse_call(head)
|
||||
};
|
||||
|
||||
self.expect(TokenKind::RightParen)?;
|
||||
result
|
||||
}
|
||||
|
||||
fn parse_if(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let cond = Box::new(self.parse_expression()?);
|
||||
let then_br = Box::new(self.parse_expression()?);
|
||||
let mut else_br = None;
|
||||
|
||||
if *self.peek() != TokenKind::RightParen {
|
||||
else_br = Some(Box::new(self.parse_expression()?));
|
||||
}
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::If { cond, then_br, else_br },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_call(&mut self, callee: Node<UntypedKind>) -> Result<Node<UntypedKind>, String> {
|
||||
let mut args = Vec::new();
|
||||
let identity = callee.identity.clone();
|
||||
|
||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||
args.push(self.parse_expression()?);
|
||||
}
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Call { callee: Box::new(callee), args },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_vector(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?; // consume '['
|
||||
let mut elements = Vec::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightBracket && *self.peek() != TokenKind::EOF {
|
||||
// Vector elements in Myc are usually just constants in a list
|
||||
let expr = self.parse_expression()?;
|
||||
elements.push(expr.eval(&mut crate::ast::nodes::Context {})); // Simple direct eval for literals
|
||||
}
|
||||
|
||||
self.expect(TokenKind::RightBracket)?;
|
||||
|
||||
Ok(Node {
|
||||
identity: Arc::new(NodeIdentity { location: token.location }),
|
||||
kind: UntypedKind::Constant(Value::List(Arc::new(elements))),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_reader_macro(&mut self, _template: UntypedKind) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?; // consume '
|
||||
let expr = self.parse_expression()?;
|
||||
|
||||
// 'x -> (quote x)
|
||||
let identity = Arc::new(NodeIdentity { location: token.location });
|
||||
let quote_id = self.make_id_node("quote", identity.clone());
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Call {
|
||||
callee: Box::new(quote_id),
|
||||
args: vec![expr],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn expect(&mut self, kind: TokenKind) -> Result<(), String> {
|
||||
let token = self.advance()?;
|
||||
if token.kind == kind {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(format!("Expected {:?}, but found {:?} at {:?}", kind, token.kind, token.location))
|
||||
}
|
||||
}
|
||||
|
||||
fn make_id_node(&self, name: &str, identity: Identity) -> Node<UntypedKind> {
|
||||
Node {
|
||||
identity,
|
||||
kind: UntypedKind::Identifier(Arc::from(name)),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user