parsed function as argument

pull/4/head
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 parser::Expr;
use parser::types::{Expr, Typehint};
const INTRINSICS: [&str; 8] = [
"write",
@ -30,6 +30,7 @@ impl std::fmt::Display for Value {
pub enum IRKind {
Value { value: Value },
Vector { values: Vec<Self> },
Tuple { values: Vec<Self> },
Unary {
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::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();
for value in values {
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());
}
(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
@ -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 {
"int" => "number".to_string(),
"bool" => "boolean".to_string(),
"string" => "string".to_string(),
"void" => "void".to_string(),
// TODO: Un-hardcode types
"vec_int" => "number[]".to_string(),
"vec_bool" => "boolean[]".to_string(),
"vec_string" => "string[]".to_string(),
_ => { dbg!(type_hint); todo!() }
Typehint::Single(t) => match t.as_str() {
"int" => "number".to_string(),
"bool" => "boolean".to_string(),
_ => t.to_string()
},
Typehint::Tuple(ts) => {
let mut types = Vec::new();
for t in ts {
types.push(gen_type_hint(&t.0));
}
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

@ -169,25 +169,4 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = Simple<char>> {
pub fn lex(src: String) -> (Option<Vec<(Token, std::ops::Range<usize>)>>, Vec<Simple<char>>) {
let (tokens, lex_error) = lexer().parse_recovery(src.as_str());
(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 lexer::Token;
pub type Spanned<T> = (T, std::ops::Range<usize>);
pub mod types;
use types::{Expr, Spanned, Typehint};
#[derive(Clone, Debug)]
pub enum Expr {
Int(i64), Float(f64), Boolean(bool),
String(String), Identifier(String),
fn typehint_parser() -> impl Parser<Token, Spanned<Typehint>, Error = Simple<Token>> + Clone {
let single = filter_map(|span, token| match token {
Token::Identifier(s) => Ok((Typehint::Single(s), span)),
_ => 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>> },
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 vector = single
.delimited_by(
just(Token::OpenBracket),
just(Token::CloseBracket),
)
.map_with_span(|arg, span| {
(Typehint::Vector(Box::new(arg)), span)
});
Let {
public: bool,
name: Spanned<String>,
type_hint: Spanned<String>,
value: Box<Spanned<Self>>,
mutable: bool,
},
Fun {
public: bool,
name: Spanned<String>,
type_hint: Spanned<String>,
args: Spanned<Vec<(Spanned<String>, Spanned<String>)>>,
body: Box<Spanned<Self>>
},
Return { expr: Box<Spanned<Self>> },
let function = single
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(
just(Token::Pipe),
just(Token::Pipe),
)
.then_ignore(just(Token::Arrow))
.then(single)
.map_with_span(|(args, ret), span| {
(Typehint::Function(args, Box::new(ret)), span)
});
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)
single
.or(tuple)
.or(vector)
.or(function)
.labelled("type hint")
}
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
.or(identifier.map(|(s, span)| (Expr::Identifier(s), span)))
.or(vector)
.or(tuple)
.labelled("atom");
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(identifier)
.then_ignore(just(Token::Colon))
.then(identifier)
.then(typehint_parser())
.then_ignore(just(Token::Assign))
.then(expr.clone())
.map(|((((public, mutable), name), type_hint), value)| {
@ -241,7 +256,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
.then(
identifier
.then_ignore(just(Token::Colon))
.then(identifier)
.then(typehint_parser())
.delimited_by(
just(Token::OpenParen),
just(Token::CloseParen),
@ -249,7 +264,7 @@ fn expr_parser() -> impl Parser<Token, Vec<Spanned<Expr>>, Error = Simple<Token>
.repeated()
)
.then_ignore(just(Token::Colon))
.then(identifier)
.then(typehint_parser())
.then_ignore(just(Token::Assign))
.then(expr.clone())
.map(|((((public, name), args), type_hint), body)| {
@ -370,23 +385,4 @@ pub fn parse(tokens: Vec<(Token, std::ops::Range<usize>)>, len: usize) -> (Optio
));
(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