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

parsed function as argument

This commit is contained in:
Natapat Samutpong 2022-04-07 15:21:29 +07:00
parent 6d41cc4ded
commit c095efdd7c
15 changed files with 149 additions and 195 deletions

View file

@ -1,5 +1,5 @@
use std::ops::Range; use std::ops::Range;
use parser::Expr; use parser::types::{Expr, Typehint};
const INTRINSICS: [&str; 8] = [ const INTRINSICS: [&str; 8] = [
"write", "write",
@ -30,6 +30,7 @@ impl std::fmt::Display for Value {
pub enum IRKind { pub enum IRKind {
Value { value: Value }, Value { value: Value },
Vector { values: Vec<Self> }, Vector { values: Vec<Self> },
Tuple { values: Vec<Self> },
Unary { Unary {
op: String, op: String,
@ -422,7 +423,7 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
Expr::String(value) => return_ok!(IRKind::Value { value: Value::String(value.clone()) }), Expr::String(value) => return_ok!(IRKind::Value { value: Value::String(value.clone()) }),
Expr::Identifier(value) => return_ok!(IRKind::Value { value: Value::Ident(value.clone()) }), Expr::Identifier(value) => return_ok!(IRKind::Value { value: Value::Ident(value.clone()) }),
Expr::Vector(values) => { v @ Expr::Vector(values) | v @ Expr::Tuple(values) => {
let mut lvalues = Vec::new(); let mut lvalues = Vec::new();
for value in values { for value in values {
let value = expr_to_ir(&value.0); let value = expr_to_ir(&value.0);
@ -430,7 +431,11 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
lvalues.push(value.0.unwrap()); lvalues.push(value.0.unwrap());
} }
(Some(IRKind::Vector { values: lvalues }), None) match v {
Expr::Vector(..) => return_ok!(IRKind::Vector { values: lvalues }),
Expr::Tuple(..) => return_ok!(IRKind::Tuple { values: lvalues }),
_ => unreachable!()
}
}, },
// Probably will never happen because it is catched in parser // Probably will never happen because it is catched in parser
@ -442,16 +447,21 @@ pub fn expr_to_ir(expr: &Expr) -> (Option<IRKind>, Option<LoweringError>) {
} }
} }
fn gen_type_hint(type_hint: &str) -> String { fn gen_type_hint(type_hint: &Typehint) -> String {
match type_hint { match type_hint {
Typehint::Single(t) => match t.as_str() {
"int" => "number".to_string(), "int" => "number".to_string(),
"bool" => "boolean".to_string(), "bool" => "boolean".to_string(),
"string" => "string".to_string(), _ => t.to_string()
"void" => "void".to_string(), },
// TODO: Un-hardcode types Typehint::Tuple(ts) => {
"vec_int" => "number[]".to_string(), let mut types = Vec::new();
"vec_bool" => "boolean[]".to_string(), for t in ts {
"vec_string" => "string[]".to_string(), types.push(gen_type_hint(&t.0));
_ => { dbg!(type_hint); todo!() } }
format!("[{}]", types.join(", "))
},
Typehint::Vector(t) => format!("{}[]", gen_type_hint(&t.0)),
Typehint::Function(_args, _ret) => {dbg!(type_hint); todo!()}, // TODO: Function type
} }
} }

View file

@ -170,24 +170,3 @@ pub fn lex(src: String) -> (Option<Vec<(Token, std::ops::Range<usize>)>>, Vec<Si
let (tokens, lex_error) = lexer().parse_recovery(src.as_str()); let (tokens, lex_error) = lexer().parse_recovery(src.as_str());
(tokens, lex_error) (tokens, lex_error)
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lex_let_simple() {
let (tokens, err) = lex("let x: Int = 1;".to_string());
assert_eq!(tokens, Some(vec![
(Token::KwLet, 0..3),
(Token::Identifier("x".to_string()), 4..5),
(Token::Colon, 5..6),
(Token::Identifier("Int".to_string()), 7..10),
(Token::Assign, 11..12),
(Token::Int(1), 13..14),
(Token::SemiColon, 14..15),
]));
assert_eq!(err, vec![]);
}
}

View file

@ -1,53 +1,53 @@
use chumsky::{prelude::*, Stream}; use chumsky::{prelude::*, Stream};
use lexer::Token; use lexer::Token;
pub type Spanned<T> = (T, std::ops::Range<usize>); pub mod types;
use types::{Expr, Spanned, Typehint};
#[derive(Clone, Debug)] fn typehint_parser() -> impl Parser<Token, Spanned<Typehint>, Error = Simple<Token>> + Clone {
pub enum Expr { let single = filter_map(|span, token| match token {
Int(i64), Float(f64), Boolean(bool), Token::Identifier(s) => Ok((Typehint::Single(s), span)),
String(String), Identifier(String), _ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))),
});
Vector(Vec<Spanned<Self>>), let tuple = single
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(
just(Token::OpenParen),
just(Token::CloseParen),
)
.map_with_span(|args, span| {
(Typehint::Tuple(args), span)
});
Unary { op: String, rhs: Box<Spanned<Self>> }, let vector = single
Binary { lhs: Box<Spanned<Self>>, op: String, rhs: Box<Spanned<Self>> }, .delimited_by(
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> }, just(Token::OpenBracket),
Pipeline { lhs: Box<Spanned<Self>>, rhs: Box<Spanned<Self>> }, just(Token::CloseBracket),
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> }, )
.map_with_span(|arg, span| {
(Typehint::Vector(Box::new(arg)), span)
});
Let { let function = single
public: bool, .separated_by(just(Token::Comma))
name: Spanned<String>, .allow_trailing()
type_hint: Spanned<String>, .delimited_by(
value: Box<Spanned<Self>>, just(Token::Pipe),
mutable: bool, just(Token::Pipe),
}, )
Fun { .then_ignore(just(Token::Arrow))
public: bool, .then(single)
name: Spanned<String>, .map_with_span(|(args, ret), span| {
type_hint: Spanned<String>, (Typehint::Function(args, Box::new(ret)), span)
args: Spanned<Vec<(Spanned<String>, Spanned<String>)>>, });
body: Box<Spanned<Self>>
},
Return { expr: Box<Spanned<Self>> },
If { single
cond: Box<Spanned<Self>>, .or(tuple)
body: Box<Spanned<Self>>, .or(vector)
else_body: Box<Spanned<Self>> .or(function)
}, .labelled("type hint")
Case {
expr: Box<Spanned<Self>>,
cases: Spanned<Vec<(Spanned<Self>, Spanned<Self>)>>,
default: Box<Spanned<Self>>
},
Do {
body: Spanned<Vec<Spanned<Self>>>
},
// Hole for positional argument(s) in piping
Hole(usize, usize), // The usize is the span of the hole (prob should be single but whatever)
} }
fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>> + Clone { fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>> + Clone {
@ -83,9 +83,24 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
) )
}); });
let tuple = expr.clone()
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(
just(Token::OpenParen),
just(Token::CloseParen),
)
.map_with_span(|args, span| {
(
Expr::Tuple(args),
span,
)
});
let atom = literal let atom = literal
.or(identifier.map(|(s, span)| (Expr::Identifier(s), span))) .or(identifier.map(|(s, span)| (Expr::Identifier(s), span)))
.or(vector) .or(vector)
.or(tuple)
.labelled("atom"); .labelled("atom");
let call = atom.clone() let call = atom.clone()
@ -219,7 +234,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
.then(just(Token::KwMut).or_not()) .then(just(Token::KwMut).or_not())
.then(identifier) .then(identifier)
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
.then(identifier) .then(typehint_parser())
.then_ignore(just(Token::Assign)) .then_ignore(just(Token::Assign))
.then(expr.clone()) .then(expr.clone())
.map(|((((public, mutable), name), type_hint), value)| { .map(|((((public, mutable), name), type_hint), value)| {
@ -241,7 +256,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
.then( .then(
identifier identifier
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
.then(identifier) .then(typehint_parser())
.delimited_by( .delimited_by(
just(Token::OpenParen), just(Token::OpenParen),
just(Token::CloseParen), just(Token::CloseParen),
@ -249,7 +264,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
.repeated() .repeated()
) )
.then_ignore(just(Token::Colon)) .then_ignore(just(Token::Colon))
.then(identifier) .then(typehint_parser())
.then_ignore(just(Token::Assign)) .then_ignore(just(Token::Assign))
.then(expr.clone()) .then(expr.clone())
.map(|((((public, name), args), type_hint), body)| { .map(|((((public, name), args), type_hint), body)| {
@ -371,22 +386,3 @@ pub fn parse(tokens: Vec<(Token, std::ops::Range<usize>)>, len: usize) -> (Optio
(ast, parse_error) (ast, parse_error)
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_simple() {
let (_, err) = parse(vec![
(Token::KwLet, 0..3),
(Token::Identifier("x".to_string()), 4..5),
(Token::Colon, 5..6),
(Token::Identifier("Int".to_string()), 7..10),
(Token::Assign, 11..12),
(Token::Int(1), 13..14),
], 15);
assert_eq!(err, vec![]);
}
}

View file

@ -0,0 +1,58 @@
pub type Spanned<T> = (T, std::ops::Range<usize>);
#[derive(Clone, Debug)]
pub enum Typehint {
Single(String), // e.g. `int`, `bool`, `string`
Tuple(Vec<Spanned<Self>>), // e.g. `(int, bool)`
Vector(Box<Spanned<Self>>), // e.g. `[int]`
Function(Vec<Spanned<Self>>, Box<Spanned<Self>>), // e.g. `(a: int, b: bool) -> string`, `(b: int) -> [bool]`
}
#[derive(Clone, Debug)]
pub enum Expr {
Int(i64), Float(f64), Boolean(bool),
String(String), Identifier(String),
Tuple(Vec<Spanned<Self>>), // Wait, its all Vec<Spanned<Self>>?
Vector(Vec<Spanned<Self>>), // Always have been
Unary { op: String, rhs: Box<Spanned<Self>> },
Binary { lhs: Box<Spanned<Self>>, op: String, rhs: Box<Spanned<Self>> },
Call { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
Pipeline { lhs: Box<Spanned<Self>>, rhs: Box<Spanned<Self>> },
Intrinsic { name: Box<Spanned<Self>>, args: Spanned<Vec<Spanned<Self>>> },
Let {
public: bool,
name: Spanned<String>,
type_hint: Spanned<Typehint>,
value: Box<Spanned<Self>>,
mutable: bool,
},
Fun {
public: bool,
name: Spanned<String>,
type_hint: Spanned<Typehint>,
args: Spanned<Vec<(Spanned<String>, Spanned<Typehint>)>>,
body: Box<Spanned<Self>>
},
Return { expr: Box<Spanned<Self>> },
If {
cond: Box<Spanned<Self>>,
body: Box<Spanned<Self>>,
else_body: Box<Spanned<Self>>
},
Case {
expr: Box<Spanned<Self>>,
cases: Spanned<Vec<(Spanned<Self>, Spanned<Self>)>>,
default: Box<Spanned<Self>>
},
Do {
body: Spanned<Vec<Spanned<Self>>>
},
// Hole for positional argument(s) in piping
Hole(usize, usize), // The usize is the span of the hole (prob should be single but whatever)
}

View file

@ -1,3 +0,0 @@
let foo: int = "123"
let bar: string = 69
let baz: bool = "true"

View file

@ -1,7 +0,0 @@
fun main: void = do
do
let foo: string = "Hello"
@write(foo)
end
@write(foo) -- TODO: This is a runtime error
end

View file

@ -1,3 +0,0 @@
fun main: void = do
@throw("woopsie")
end

View file

@ -1,3 +0,0 @@
fun main: void = do
@writse() -- Unknown intrinsic
end

View file

@ -1,3 +0,0 @@
pub fun print_something: void = @emit("console.log('something')")
fun main: void = do end

View file

@ -1,15 +0,0 @@
fun main: void = do
if true then
@write("True")
else
@write("False")
end
if true then
do
@write("True")
end
else
@write("False")
end
end

View file

@ -1,12 +0,0 @@
fun main: void = do
let foo: int = 3
match foo with
| 1 -> @write("One")
| 2 -> @write("Two")
| 3 -> do
@write("Three")
end
| else @write("idk")
end
end

View file

@ -1,14 +0,0 @@
fun foo (xs: int): int = return xs + 1
fun bar (xs: int) (x: int): int = return xs - x
fun main: void = do
foo(69) -- 69 + 1 => 70
|> bar(_, 1) -- '70 - 1 => 69
|> @write(_) -- '69 => stdout
@write("\n")
foo(60) -- 60 + 1 => 61
|> bar(130, _) -- 130 - '61 => 69
|> @write(_) -- '69 => stdout
end

View file

@ -1,19 +0,0 @@
fun foo (xs: int) : int = return xs + 1
fun bar (xs: int) (ys: int) : int = return xs + ys
fun baz (xs: int) (ys: int) (zs: int): int = return xs + ys + zs
fun qux (xs: int) : int = return xs - 1
fun quux (xs: int) (xy: int) : int = return xs - 2 + xy
fun main: void = do
66
|> foo(_)
|> bar(_, 1)
|> baz(1, 2, _)
|> qux(_)
|> quux(1, _)
|> @write(_)
210
|> bar(_, _)
|> @write(_)
end

View file

@ -1,16 +0,0 @@
fun main: void = do
let str: string = "Hello, World"
-- Matching string(s)
match str with
| "Hello, World" -> @write("yes\n")
| else @write("no\n")
end
-- Indexing character in string
let foo: string = @get(str, 0)
match foo with
| "H" -> @write("still yes")
| else @write("no H")
end
end

6
example/tuples.hz Normal file
View file

@ -0,0 +1,6 @@
fun test (foo: int) (bar: int) : int = foo * bar
fun f (fn: |int, int| -> int) (x: int) : int = fn(x)
fun main: void = do
let x : int = 20
end