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:
parent
24daf588b0
commit
028c58980c
|
@ -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);
|
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod model;
|
pub mod model;
|
||||||
pub mod helper;
|
pub mod helper;
|
||||||
|
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
|
pub mod parser;
|
|
@ -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,
|
||||||
|
@ -26,4 +30,125 @@ impl<'a> Tokens<'a> {
|
||||||
pub fn new(tokens: &'a [Token]) -> Self {
|
pub fn new(tokens: &'a [Token]) -> Self {
|
||||||
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
142
src/front/parser.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue