1
1
Fork 0
mirror of https://github.com/azur1s/bobbylisp.git synced 2024-10-16 02:37:40 -05:00

some AST generation (let, ident, etc.)

also no more formal commit message because im lazy
This commit is contained in:
Natapat Samutpong 2022-02-12 14:29:33 +07:00
parent 24daf588b0
commit 028c58980c
5 changed files with 276 additions and 7 deletions

View file

@ -1,3 +1,2 @@
let msg :: String = "Hello, World"; let foo :: String = "Hello, ";
func add2 :: (a: Int, b: Int) -> Int = a + b; let bar :: String = "World!";
func main :: () = puts (msg);

View file

@ -2,3 +2,4 @@ pub mod model;
pub mod helper; pub mod helper;
pub mod lex; pub mod lex;
pub mod parser;

View file

@ -1,3 +1,7 @@
use std::iter::Enumerate;
use nom::{InputTake, Needed, InputIter, InputLength};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Token { pub enum Token {
Illegal, EndOfFile, Illegal, EndOfFile,
@ -27,3 +31,124 @@ impl<'a> Tokens<'a> {
Tokens { tokens, start: 0, end: tokens.len(), } Tokens { tokens, start: 0, end: tokens.len(), }
} }
} }
impl<'a> InputTake for Tokens<'a> {
#[inline]
fn take(&self, count: usize) -> Self {
Tokens {
tokens: &self.tokens[0..count],
start: 0,
end: count,
}
}
#[inline]
fn take_split(&self, count: usize) -> (Self, Self) {
let (prefix, suffix) = self.tokens.split_at(count);
let first = Tokens {
tokens: prefix,
start: 0,
end: prefix.len(),
};
let second = Tokens {
tokens: suffix,
start: 0,
end: suffix.len(),
};
(second, first)
}
}
impl<'a> InputLength for Tokens<'a> {
#[inline]
fn input_len(&self) -> usize {
self.tokens.len()
}
}
impl<'a> InputIter for Tokens<'a> {
type Item = &'a Token;
type Iter = Enumerate<::std::slice::Iter<'a, Token>>;
type IterElem = ::std::slice::Iter<'a, Token>;
#[inline]
fn iter_indices(&self) -> Enumerate<::std::slice::Iter<'a, Token>> {
self.tokens.iter().enumerate()
}
#[inline]
fn iter_elements(&self) -> ::std::slice::Iter<'a, Token> {
self.tokens.iter()
}
#[inline]
fn position<P>(&self, predicate: P) -> Option<usize>
where P: Fn(Self::Item) -> bool {
self.tokens.iter().position(predicate)
}
#[inline]
fn slice_index(&self, count: usize) -> Result<usize, Needed> {
if self.tokens.len() >= count { Ok(count) }
else { Err(Needed::Unknown) }
}
}
pub type Program = Vec<Stmt>;
#[derive(Clone, Debug, PartialEq)]
pub enum Stmt {
Let(Ident, Ident, Expr),
Func(Ident, Vec<Ident>, Vec<Stmt>),
}
#[derive(Clone, Debug, PartialEq)]
pub enum Expr {
Ident(Ident), Literal(Literal),
Array(Vec<Expr>),
Prefix(Prefix, Box<Expr>),
Infix(Infix, Box<Expr>, Box<Expr>),
If {
cond: Box<Expr>,
then: Program,
else_: Option<Program>,
},
Func {
name: Ident,
args: Vec<Ident>,
body: Program,
},
Call {
func: Box<Expr>,
args: Vec<Expr>,
},
}
#[derive(Clone, Debug, PartialEq)]
pub enum Literal {
Int(i64), Bool(bool), String(String),
}
#[derive(Clone, Debug, PartialEq)]
pub struct Ident(pub String);
#[derive(Clone, Debug, PartialEq)]
pub enum Prefix {
Not,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Infix {
Plus, Minus, Mul, Div,
Eq, NEq, Lt, Gt, Lte, Gte,
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub enum Precedence {
Lowest,
Equals,
LessGreater,
Sum,
Product,
Call,
}

142
src/front/parser.rs Normal file
View file

@ -0,0 +1,142 @@
use nom::{
bytes::complete::take,
combinator::{verify, map},
Err,
IResult, sequence::{terminated, tuple}, multi::many0, branch::alt, error::{Error, ErrorKind},
};
use super::model::{Token, Tokens, Precedence, Infix, Program, Stmt, Expr, Ident, Literal};
macro_rules! tag_token (
($func_name:ident, $tag: expr) => (
fn $func_name(tokens: Tokens) -> IResult<Tokens, Tokens> {
verify(take(1usize), |t: &Tokens| t.tokens[0] == $tag)(tokens)
}
)
);
tag_token!(tag_let, Token::Let);
tag_token!(tag_assign, Token::Assign);
tag_token!(tag_typehint, Token::Typehint);
tag_token!(tag_semicolon, Token::Semicolon);
tag_token!(tag_end_of_file, Token::EndOfFile);
fn infix_operator(token: &Token) -> (Precedence, Option<Infix>) {
match *token {
Token::Eq => (Precedence::Equals, Some(Infix::Eq)),
Token::NEq => (Precedence::Equals, Some(Infix::NEq)),
Token::Lt => (Precedence::LessGreater, Some(Infix::Lt)),
Token::Gt => (Precedence::LessGreater, Some(Infix::Gt)),
Token::Lte => (Precedence::LessGreater, Some(Infix::Lte)),
Token::Gte => (Precedence::LessGreater, Some(Infix::Gte)),
Token::Plus => (Precedence::Sum, Some(Infix::Plus)),
Token::Minus => (Precedence::Sum, Some(Infix::Minus)),
Token::Mul => (Precedence::Product, Some(Infix::Mul)),
Token::Div => (Precedence::Product, Some(Infix::Div)),
Token::LParen => (Precedence::Call, None),
_ => (Precedence::Lowest, None),
}
}
fn parse_literal(input: Tokens) -> IResult<Tokens, Literal> {
let (i1, t1) = take(1usize)(input)?;
if t1.tokens.is_empty() { Err(Err::Error(Error::new(input, ErrorKind::Tag))) }
else {
match t1.tokens[0].clone() {
Token::Int(i) => Ok((i1, Literal::Int(i))),
Token::String(s) => Ok((i1, Literal::String(s))),
Token::Bool(b) => Ok((i1, Literal::Bool(b))),
_ => Err(Err::Error(Error::new(input, ErrorKind::Tag))),
}
}
}
fn parse_literal_expr(input: Tokens) -> IResult<Tokens, Expr> {
map(parse_literal, Expr::Literal)(input)
}
fn parse_atom_expr(input: Tokens) -> IResult<Tokens, Expr> {
alt((
parse_literal_expr,
parse_ident_expr,
))(input)
}
fn parse_ident(input: Tokens) -> IResult<Tokens, Ident> {
let (i1, t1) = take(1usize)(input)?;
if t1.tokens.is_empty() { Err(Err::Error(Error::new(input, ErrorKind::Tag))) }
else {
match t1.tokens[0].clone() {
Token::Identifier(name) => Ok((i1, Ident(name))),
_ => Err(Err::Error(Error::new(input, ErrorKind::Tag))),
}
}
}
fn parse_ident_expr(input: Tokens) -> IResult<Tokens, Expr> {
map(parse_ident, Expr::Ident)(input)
}
fn parse_let(input: Tokens) -> IResult<Tokens, Stmt> {
map(
tuple((
tag_let,
parse_ident,
tag_typehint,
parse_ident,
tag_assign,
parse_expr_lowest,
tag_semicolon,
)),
|(_, ident, _, typehint, _, expr, _)| Stmt::Let(ident, typehint, expr),
)(input)
}
fn parse_expr(input: Tokens, precedence: Precedence, left: Expr) -> IResult<Tokens, Expr> {
let (i1, t1) = take(1usize)(input)?;
if t1.tokens.is_empty() { Ok((i1, left)) }
else {
let p = infix_operator(&t1.tokens[0]);
match p {
(Precedence::Call, _) if precedence < Precedence::Call => {
// let (i2, left2) = parse_call_expr(input, left)?;
// parse_expr(i2, precedence, left2)
todo!()
},
(ref peek, _) if precedence < *peek => {
// let (i2, left2) = parse_infix_expr(input, left)?;
// parse_expr(i2, precedence, left2)
todo!()
},
_ => Ok((input, left)),
}
}
}
fn parse_expr_with(input: Tokens, precedence: Precedence) -> IResult<Tokens, Expr> {
let (i1, left) = parse_atom_expr(input)?;
parse_expr(i1, precedence, left)
}
fn parse_expr_lowest(input: Tokens) -> IResult<Tokens, Expr> {
parse_expr_with(input, Precedence::Lowest)
}
fn parse_stmt(input: Tokens) -> IResult<Tokens, Stmt> {
alt((
parse_let,
))(input)
}
fn parse_program(input: Tokens) -> IResult<Tokens, Program> {
terminated(many0(parse_stmt), tag_end_of_file)(input)
}
pub struct Parser;
impl Parser {
pub fn parse(tokens: Tokens) -> IResult<Tokens, Program> {
parse_program(tokens)
}
}

View file

@ -7,15 +7,17 @@ pub mod args;
use args::{Args, Options}; use args::{Args, Options};
pub mod front; pub mod front;
use front::lex::Lexer; use front::{lex::Lexer, parser::Parser, model::Tokens};
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
match args.options { match args.options {
Options::Compile { input: src, ast: _print_ast } => { Options::Compile { input: src, ast: _print_ast } => {
let bytes: Vec<u8> = fs::read(src).unwrap(); let bytes: Vec<u8> = fs::read(src).unwrap();
let tokens = Lexer::lex_tokens(&bytes); let (_errs_, tokens) = Lexer::lex_tokens(&bytes).unwrap();
println!("{:?}", tokens); let tokens = Tokens::new(&tokens);
let (_errs_, ast) = Parser::parse(tokens).unwrap();
println!("{:#?}", ast);
}, },
} }
} }