Compare commits
No commits in common. "0337e4f5ff619220eec14f7d534fffa971d22916" and "c02e1c1f8e69099af01b6b4312579dd3a3fd4f2c" have entirely different histories.
0337e4f5ff
...
c02e1c1f8e
24
CHANGELOG.md
24
CHANGELOG.md
@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
- Parse __more__ binary operators
|
- Parse multiple statements
|
||||||
|
- Parse binary operators
|
||||||
- Parse more complex bindings
|
- Parse more complex bindings
|
||||||
|
- Parse block of code
|
||||||
- Watch mode
|
- Watch mode
|
||||||
- Improve error messages
|
- Improve error messages
|
||||||
- Parse other language constructions
|
- Parse other language constructions
|
||||||
@ -12,30 +14,10 @@
|
|||||||
- Namespace identifiers in the symbol table
|
- Namespace identifiers in the symbol table
|
||||||
- Stdlib
|
- Stdlib
|
||||||
- Document code
|
- Document code
|
||||||
- Watch mode
|
|
||||||
- Formatter
|
|
||||||
- Simple language server
|
|
||||||
|
|
||||||
## v0.0.10
|
|
||||||
|
|
||||||
- [ ] Typecheck current AST
|
|
||||||
|
|
||||||
## v0.0.9
|
|
||||||
|
|
||||||
- [ ] Hand made CLI, remove clap
|
|
||||||
- [ ] Compile a single file
|
|
||||||
- [ ] Implement code generation for ast nodes implemented as of now
|
|
||||||
- [ ] Display error messages during compilation
|
|
||||||
- [ ] Improve errro messages
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## v0.0.8
|
## v0.0.8
|
||||||
|
|
||||||
- Parse block of code
|
|
||||||
- Parse multiple statements inside a block
|
- Parse multiple statements inside a block
|
||||||
- Parse unary operator (`!` & `-`)
|
|
||||||
- Parse binary operators
|
|
||||||
|
|
||||||
|
|
||||||
## v0.0.7
|
## v0.0.7
|
||||||
|
23
CLI.md
23
CLI.md
@ -1,23 +0,0 @@
|
|||||||
The THP compiler & formatter, v0.0.1
|
|
||||||
|
|
||||||
Usage: `thp [command] [options]`
|
|
||||||
|
|
||||||
## Commands
|
|
||||||
|
|
||||||
c _file_ Compiles `file` in-place
|
|
||||||
f _file_ Formats `file`
|
|
||||||
r Starts the REPL
|
|
||||||
|
|
||||||
init Initializes a new project in the current directory
|
|
||||||
build, b Builds the project
|
|
||||||
fmt Formats all files in the project
|
|
||||||
watch Starts compilation of the project in watch mode
|
|
||||||
|
|
||||||
|
|
||||||
help, h Print this message & exit
|
|
||||||
|
|
||||||
## General options
|
|
||||||
|
|
||||||
-h, --help Print command-specific usage
|
|
||||||
|
|
||||||
|
|
@ -18,12 +18,6 @@ impl Transpilable for Expression {
|
|||||||
Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }),
|
Expression::Boolean(value) => String::from(if *value { "true" } else { "false" }),
|
||||||
Expression::Identifier(value) => format!("{}", *value),
|
Expression::Identifier(value) => format!("{}", *value),
|
||||||
Expression::FunctionCall(_) => todo!("FunctionCall codegen is not implemented yet"),
|
Expression::FunctionCall(_) => todo!("FunctionCall codegen is not implemented yet"),
|
||||||
Expression::BinaryOperator(_, _, _) => {
|
|
||||||
todo!("BinaryOperator codegen is not implemented yet")
|
|
||||||
}
|
|
||||||
Expression::UnaryOperator(_, _) => {
|
|
||||||
todo!("UnaryOperator codegen is not implemented yet")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,4 @@ pub enum Expression {
|
|||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Identifier(Box<String>),
|
Identifier(Box<String>),
|
||||||
FunctionCall(FunctionCall),
|
FunctionCall(FunctionCall),
|
||||||
UnaryOperator(Box<String>, Box<Expression>),
|
|
||||||
BinaryOperator(Box<Expression>, Box<Expression>, Box<String>),
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,20 @@
|
|||||||
use crate::{
|
use super::{ast::Expression, functions::function_call, ParseResult};
|
||||||
lexic::token::{Token, TokenType},
|
use crate::lexic::token::{Token, TokenType};
|
||||||
syntax::{ast::Expression, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// This grammar may not be up to date. Refer to the spec for the latest grammar.
|
/// An expression can be:
|
||||||
///
|
///
|
||||||
/// ```ebnf
|
/// - A number
|
||||||
/// primary = number | string | boolean | identifier | ("(", expression, ")");
|
/// - A string
|
||||||
/// ```
|
/// - A boolean
|
||||||
|
/// - An identifier
|
||||||
|
/// - A function call
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
||||||
/*
|
|
||||||
TODO: Incorporate function_call into the grammar, figure out its precedence.
|
|
||||||
match function_call::try_parse(tokens, pos) {
|
match function_call::try_parse(tokens, pos) {
|
||||||
super::ParseResult::Ok(function_call, next_pos) => {
|
super::ParseResult::Ok(function_call, next_pos) => {
|
||||||
return ParseResult::Ok::<_, ()>(Expression::FunctionCall(function_call), next_pos)
|
return ParseResult::Ok::<_, ()>(Expression::FunctionCall(function_call), next_pos)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
*/
|
|
||||||
|
|
||||||
match tokens.get(pos) {
|
match tokens.get(pos) {
|
||||||
Some(token) => match token.token_type {
|
Some(token) => match token.token_type {
|
||||||
@ -34,27 +31,12 @@ pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()>
|
|||||||
Expression::Identifier(Box::new(token.value.clone())),
|
Expression::Identifier(Box::new(token.value.clone())),
|
||||||
pos + 1,
|
pos + 1,
|
||||||
),
|
),
|
||||||
TokenType::LeftParen => parse_parenthesized_expression(tokens, pos),
|
|
||||||
_ => ParseResult::Unmatched,
|
_ => ParseResult::Unmatched,
|
||||||
},
|
},
|
||||||
None => ParseResult::Unmatched,
|
None => ParseResult::Unmatched,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_parenthesized_expression(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
let expression = super::try_parse(tokens, pos + 1);
|
|
||||||
match expression {
|
|
||||||
ParseResult::Ok(expression, next_pos) => match tokens.get(next_pos) {
|
|
||||||
Some(token) => match token.token_type {
|
|
||||||
TokenType::RightParen => ParseResult::Ok(expression, next_pos + 1),
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
},
|
|
||||||
None => ParseResult::Unmatched,
|
|
||||||
},
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
@ -1,49 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
lexic::token::Token,
|
|
||||||
syntax::{ast::Expression, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parses a factor expression.
|
|
||||||
///
|
|
||||||
/// ```ebnf
|
|
||||||
/// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
|
||||||
/// ```
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
let (term, next_pos) = match super::term::try_parse(tokens, pos) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
|
||||||
_ => return ParseResult::Unmatched,
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, term)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_many(
|
|
||||||
tokens: &Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
prev_expr: Expression,
|
|
||||||
) -> ParseResult<Expression, ()> {
|
|
||||||
// comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
|
||||||
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(token)
|
|
||||||
if token.value == "<"
|
|
||||||
|| token.value == "<="
|
|
||||||
|| token.value == ">"
|
|
||||||
|| token.value == ">=" =>
|
|
||||||
{
|
|
||||||
match super::term::try_parse(tokens, pos + 1) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
|
||||||
let expr = Expression::BinaryOperator(
|
|
||||||
Box::new(prev_expr),
|
|
||||||
Box::new(expr),
|
|
||||||
Box::new(token.value.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
|
||||||
}
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
lexic::token::Token,
|
|
||||||
syntax::{ast::Expression, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parses a factor expression.
|
|
||||||
///
|
|
||||||
/// ```ebnf
|
|
||||||
/// equality = comparison, (("==" | "!="), comparison )*;
|
|
||||||
/// ```
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
let (comparison, next_pos) = match super::comparison::try_parse(tokens, pos) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
|
||||||
_ => return ParseResult::Unmatched,
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, comparison)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_many(
|
|
||||||
tokens: &Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
prev_expr: Expression,
|
|
||||||
) -> ParseResult<Expression, ()> {
|
|
||||||
// equality = comparison, (("==" | "!="), comparison )*;
|
|
||||||
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(token) if token.value == "==" || token.value == "!=" => {
|
|
||||||
match super::comparison::try_parse(tokens, pos + 1) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
|
||||||
let expr = Expression::BinaryOperator(
|
|
||||||
Box::new(prev_expr),
|
|
||||||
Box::new(expr),
|
|
||||||
Box::new(token.value.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
|
||||||
}
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
lexic::token::Token,
|
|
||||||
syntax::{ast::Expression, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parses a factor expression.
|
|
||||||
///
|
|
||||||
/// ```ebnf
|
|
||||||
/// factor = unary, (("/" | "*"), unary)*;
|
|
||||||
/// ```
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
let (unary, next_pos) = match super::unary::try_parse(tokens, pos) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
|
||||||
_ => return ParseResult::Unmatched,
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, unary)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_many(
|
|
||||||
tokens: &Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
prev_expr: Expression,
|
|
||||||
) -> ParseResult<Expression, ()> {
|
|
||||||
// (("/" | "*"), unary)*
|
|
||||||
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(token) if token.value == "/" || token.value == "*" => {
|
|
||||||
match super::unary::try_parse(tokens, pos + 1) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
|
||||||
let expr = Expression::BinaryOperator(
|
|
||||||
Box::new(prev_expr),
|
|
||||||
Box::new(expr),
|
|
||||||
Box::new(token.value.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
|
||||||
}
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
use super::{ast::Expression, ParseResult};
|
|
||||||
use crate::lexic::token::Token;
|
|
||||||
|
|
||||||
mod comparison;
|
|
||||||
mod equality;
|
|
||||||
mod factor;
|
|
||||||
mod primary;
|
|
||||||
mod term;
|
|
||||||
mod unary;
|
|
||||||
|
|
||||||
/// Expression is defined in the grammar.
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
return equality::try_parse(tokens, pos);
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
lexic::token::Token,
|
|
||||||
syntax::{ast::Expression, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parses a factor expression.
|
|
||||||
///
|
|
||||||
/// ```ebnf
|
|
||||||
/// term = factor, (("-" | "+"), factor)*;
|
|
||||||
/// ```
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
let (factor, next_pos) = match super::factor::try_parse(tokens, pos) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => (expr, next_pos),
|
|
||||||
_ => return ParseResult::Unmatched,
|
|
||||||
};
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, factor)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_many(
|
|
||||||
tokens: &Vec<Token>,
|
|
||||||
pos: usize,
|
|
||||||
prev_expr: Expression,
|
|
||||||
) -> ParseResult<Expression, ()> {
|
|
||||||
// term = factor, (("-" | "+"), factor)*;
|
|
||||||
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(token) if token.value == "+" || token.value == "-" => {
|
|
||||||
match super::factor::try_parse(tokens, pos + 1) {
|
|
||||||
ParseResult::Ok(expr, next_pos) => {
|
|
||||||
let expr = Expression::BinaryOperator(
|
|
||||||
Box::new(prev_expr),
|
|
||||||
Box::new(expr),
|
|
||||||
Box::new(token.value.clone()),
|
|
||||||
);
|
|
||||||
|
|
||||||
parse_many(tokens, next_pos, expr)
|
|
||||||
}
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => ParseResult::Ok(prev_expr, pos),
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
lexic::token::Token,
|
|
||||||
syntax::{ast::Expression, expression::primary, ParseResult},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Parses an unary expression.
|
|
||||||
///
|
|
||||||
/// ```ebnf
|
|
||||||
/// unary = ("!" | "-"), expression
|
|
||||||
/// | primary;
|
|
||||||
/// ```
|
|
||||||
pub fn try_parse(tokens: &Vec<Token>, pos: usize) -> ParseResult<Expression, ()> {
|
|
||||||
match tokens.get(pos) {
|
|
||||||
Some(token) if token.value == "!" || token.value == "-" => {
|
|
||||||
match super::try_parse(tokens, pos + 1) {
|
|
||||||
ParseResult::Ok(expression, next_pos) => ParseResult::Ok(
|
|
||||||
Expression::UnaryOperator(Box::new(token.value.clone()), Box::new(expression)),
|
|
||||||
next_pos,
|
|
||||||
),
|
|
||||||
_ => ParseResult::Unmatched,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => primary::try_parse(tokens, pos),
|
|
||||||
}
|
|
||||||
}
|
|
@ -9,7 +9,6 @@ A module is (commonly) a single source file.
|
|||||||
module = top level declaration*
|
module = top level declaration*
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Top level declaration
|
## Top level declaration
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
@ -20,10 +19,18 @@ top level declaration = function declaration
|
|||||||
## Function declaration
|
## Function declaration
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
function declaration = "fun", identifier, params list, return type?, block;
|
function declaration = "fun", identifier, params list, return type?, block
|
||||||
|
```
|
||||||
|
|
||||||
params list = "(", ")";
|
### Params list
|
||||||
|
|
||||||
|
```ebnf
|
||||||
|
params list = "(", ")"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Return type
|
||||||
|
|
||||||
|
```ebnf
|
||||||
return type = ;
|
return type = ;
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -31,65 +38,28 @@ return type = ;
|
|||||||
### Block
|
### Block
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
block = "{", (statement, (new line, statement)*)?, "}"
|
block = "{", (statement, (new line, statement)*)?, "}"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Statement
|
### Statement
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
statement = binding
|
statement = function call | binding
|
||||||
| function call
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Function call
|
## Function call
|
||||||
|
|
||||||
```ebnf
|
```ebnf
|
||||||
function call = identifier, arguments list;
|
function call = identifier, arguments list
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Arguments list
|
||||||
|
|
||||||
|
```ebnf
|
||||||
arguments list = "(", ")"
|
arguments list = "(", ")"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Binding
|
|
||||||
|
|
||||||
```ebnf
|
|
||||||
binding = ("val" | "var"), identifier, "=", expression
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Operator precedence
|
|
||||||
|
|
||||||
From highest to lowest:
|
|
||||||
|
|
||||||
- `== !=`, left associative
|
|
||||||
- `> >= < <=`, left associative
|
|
||||||
- `- +`, left associative
|
|
||||||
- `/ *`, left associative
|
|
||||||
- `! -`, left associative
|
|
||||||
|
|
||||||
## Expression
|
|
||||||
|
|
||||||
```ebnf
|
|
||||||
expression = equality;
|
|
||||||
|
|
||||||
equality = comparison, (("==" | "!="), comparison )*;
|
|
||||||
|
|
||||||
comparison = term, ((">" | ">=" | "<" | "<="), term)*;
|
|
||||||
|
|
||||||
term = factor, (("-" | "+"), factor)*;
|
|
||||||
|
|
||||||
factor = unary, (("/" | "*"), unary)*;
|
|
||||||
|
|
||||||
unary = ("!" | "-"), expression
|
|
||||||
| primary;
|
|
||||||
|
|
||||||
function call = primary, (arguments list)?;
|
|
||||||
|
|
||||||
primary = number | string | boolean | identifier | ("(", expression, ")");
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user