Skip to content

Commit 73f5395

Browse files
committed
Implemented compiler
1 parent aff27b8 commit 73f5395

File tree

14 files changed

+635
-33
lines changed

14 files changed

+635
-33
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ target/
44
# IntelliJ IDEA
55
.idea/
66
*.iml
7+
8+
# Compiler test
9+
!test/target/

Cargo.lock

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9+
proc-exit = "1.0.3"
910
clap = { version = "3.2.12", features = ["derive"] }
11+
lazy_static = "1.4.0"

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Density Function Language
2+
A language for writing Minecraft density functions.
3+
4+
## Usage
5+
```
6+
density_function_lang.exe main.densityfunction --target-dir target
7+
```
8+
9+
## Examples
10+
See [test/main.densityfunction](test/main.densityfunction).

src/compiler/ast.rs

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
use std::fmt::{Debug, Formatter};
22
use crate::compiler::lexer::Token;
33

4+
#[derive(Clone)]
45
pub enum Stmt {
6+
Template {
7+
name: Token,
8+
args: Vec<Token>,
9+
expr: Expr,
10+
},
11+
512
Function {
613
name: Token,
714
expr: Expr,
@@ -13,13 +20,20 @@ pub enum Stmt {
1320
impl Debug for Stmt {
1421
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1522
match self {
16-
Stmt::Function { name, expr } => write!(f, "function {} = {:?};", name.source(), expr),
23+
Stmt::Template { name, args, expr } =>
24+
write!(f, "template {}({}) = {:?};", name.source(), args.iter()
25+
.map(|arg| arg.source().to_owned())
26+
.collect::<Vec<String>>().join(", "), expr),
27+
28+
Stmt::Function { name, expr } =>
29+
write!(f, "function {} = {:?};", name.source(), expr),
1730

1831
Stmt::Error => write!(f, "Error;")
1932
}
2033
}
2134
}
2235

36+
#[derive(Clone)]
2337
pub enum Expr {
2438
ConstantFloat(f32),
2539
ConstantInt(i32),
@@ -39,14 +53,17 @@ pub enum Expr {
3953
},
4054
FunctionCall {
4155
receiver: Option<Box<Expr>>,
42-
callee: Box<Expr>,
56+
name: Token,
4357
args: Vec<Expr>,
4458
},
4559
Member {
4660
receiver: Box<Expr>,
4761
name: Token,
4862
},
4963

64+
Object(Vec<(Token, Expr)>),
65+
Array(Vec<Expr>),
66+
5067
Error,
5168
}
5269

@@ -60,19 +77,57 @@ impl Debug for Expr {
6077
Expr::Group(expr) => write!(f, "{:?}", expr),
6178
Expr::UnaryOperator { operator, expr } => write!(f, "({}{:?})", operator.source(), expr),
6279
Expr::BinaryOperator { left, operator, right } => write!(f, "({:?} {} {:?})", left, operator.source(), right),
63-
Expr::FunctionCall { receiver, callee, args } => {
80+
Expr::FunctionCall { receiver, name, args } => {
6481
write!(f, "(")?;
6582

6683
if let Some(receiver) = receiver {
6784
write!(f, "{:?}.", receiver)?;
6885
}
6986

70-
write!(f, "{:?}({}))", callee, args.iter()
87+
write!(f, "{}({}))", name, args.iter()
7188
.map(|expr| format!("{:?}", expr))
7289
.collect::<Vec<String>>().join(", "))
7390
},
7491
Expr::Member { receiver, name } => write!(f, "({:?}.{})", receiver, name.source()),
92+
93+
// Copied from Debug for JsonElement
94+
Expr::Object(fields) => write!(f, "{{{}}}", fields.iter()
95+
.map(|(key, field)| format!("{}: {:?}", key.source(), field)).collect::<Vec<String>>()
96+
.join(", ")),
97+
Expr::Array(elements) => write!(f, "[{}]", elements.iter()
98+
.map(|element| format!("{:?}", element)).collect::<Vec<String>>()
99+
.join(", ")),
100+
75101
Expr::Error => write!(f, "Error"),
76102
}
77103
}
78104
}
105+
106+
#[derive(Clone)]
107+
pub enum JsonElement {
108+
ConstantFloat(f32),
109+
ConstantInt(i32),
110+
ConstantString(String),
111+
112+
Object(Vec<(String, JsonElement)>),
113+
Array(Vec<JsonElement>),
114+
115+
Error,
116+
}
117+
118+
impl Debug for JsonElement {
119+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
120+
match self {
121+
JsonElement::ConstantFloat(value) => write!(f, "{}", value),
122+
JsonElement::ConstantInt(value) => write!(f, "{}", value),
123+
JsonElement::ConstantString(value) => write!(f, "\"{}\"", value),
124+
JsonElement::Object(fields) => write!(f, "{{{}}}", fields.iter()
125+
.map(|(key, field)| format!("{}: {:?}", key, field)).collect::<Vec<String>>()
126+
.join(", ")),
127+
JsonElement::Array(elements) => write!(f, "[{}]", elements.iter()
128+
.map(|element| format!("{:?}", element)).collect::<Vec<String>>()
129+
.join(", ")),
130+
JsonElement::Error => write!(f, "Error"),
131+
}
132+
}
133+
}

src/compiler/compiler.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use crate::compiler::ast::{Expr, JsonElement, Stmt};
2+
use crate::compiler::lexer::{Token, TokenPos};
3+
4+
struct Template {
5+
name: String, // Can be identifiers or operator names (like `+`)
6+
args: Vec<String>,
7+
expr: Expr,
8+
}
9+
10+
pub struct Compiler {
11+
templates: Vec<Template>,
12+
template_args: Vec<(String, JsonElement)>,
13+
14+
output_functions: Vec<(String, JsonElement)>,
15+
16+
had_error: bool, panic_mode: bool,
17+
}
18+
19+
impl Compiler {
20+
pub fn new() -> Compiler {
21+
Compiler {
22+
templates: vec![],
23+
template_args: vec![],
24+
25+
output_functions: vec![],
26+
27+
had_error: false, panic_mode: false,
28+
}
29+
}
30+
31+
pub fn compile(mut self, statements: Vec<Stmt>) -> Vec<(String, JsonElement)> {
32+
for stmt in statements {
33+
self.compile_statement(stmt);
34+
}
35+
36+
self.output_functions
37+
}
38+
39+
fn compile_statement(&mut self, stmt: Stmt) {
40+
match stmt {
41+
Stmt::Template { name, args, expr } => self.compile_template(name, args, expr),
42+
Stmt::Function { name, expr } => self.compile_function(name, expr),
43+
Stmt::Error => {},
44+
}
45+
}
46+
47+
fn compile_template(&mut self, name: Token, args: Vec<Token>, expr: Expr) {
48+
if self.templates.iter().any(|template| *template.name == *name.source() && template.args.len() == args.len()) {
49+
self.error_at(Some(*name.start()), "Tried to define multiple templates with the same name", false);
50+
return;
51+
}
52+
53+
self.templates.push(Template {
54+
name: name.source().to_owned(),
55+
args: args.iter().map(|arg| arg.source().to_owned()).collect(),
56+
expr
57+
})
58+
}
59+
60+
fn compile_function(&mut self, name: Token, expr: Expr) {
61+
if self.output_functions.iter().any(|(function_name, _)| *function_name == *name.source()) {
62+
self.error_at(Some(*name.start()), "Tried to define multiple density functions with the same name", false);
63+
return;
64+
}
65+
66+
let expr = self.compile_expr(expr);
67+
self.output_functions.push((name.source().to_owned(), expr));
68+
}
69+
70+
fn compile_expr(&mut self, expr: Expr) -> JsonElement {
71+
match expr {
72+
Expr::ConstantFloat(value) => JsonElement::ConstantFloat(value),
73+
Expr::ConstantInt(value) => JsonElement::ConstantInt(value),
74+
Expr::ConstantString(value) => JsonElement::ConstantString(value),
75+
Expr::Identifier(id) => {
76+
if let Some((_, element)) = self.template_args.iter().rfind(|(name, _)| *name == *id.source()) {
77+
element.clone()
78+
} else {
79+
self.error_at(Some(*id.start()), &format!("Unresolved reference: {}", id.source()), false);
80+
JsonElement::ConstantString(id.source().to_owned())
81+
}
82+
},
83+
Expr::Group(expr) => self.compile_expr(*expr),
84+
Expr::UnaryOperator { operator, expr } => {
85+
let compiled_expr = self.compile_expr(*expr);
86+
87+
self.evaluate_template(None, operator, vec![compiled_expr])
88+
},
89+
Expr::BinaryOperator { left, operator, right } => {
90+
let compiled_left = self.compile_expr(*left);
91+
let compiled_right = self.compile_expr(*right);
92+
93+
self.evaluate_template(None, operator, vec![compiled_left, compiled_right])
94+
},
95+
Expr::FunctionCall { receiver, name, args } => {
96+
let compiled_receiver = receiver.map(|receiver| self.compile_expr(*receiver));
97+
let compiled_args = args.into_iter().map(|arg| self.compile_expr(arg)).collect();
98+
99+
self.evaluate_template(compiled_receiver, name, compiled_args)
100+
},
101+
Expr::Member { name, .. } => {
102+
self.error_at(Some(*name.start()), &format!("Unresolved reference: {}", name.source()), false);
103+
JsonElement::Error
104+
},
105+
Expr::Object(fields) => {
106+
JsonElement::Object(fields.into_iter().map(|(name, field)| (name.source().to_owned(), self.compile_expr(field))).collect())
107+
},
108+
Expr::Array(elements) => {
109+
JsonElement::Array(elements.into_iter().map(|element| self.compile_expr(element)).collect())
110+
},
111+
Expr::Error => JsonElement::Error,
112+
}
113+
}
114+
115+
fn evaluate_template(&mut self, receiver: Option<JsonElement>, name: Token, args: Vec<JsonElement>) -> JsonElement {
116+
if let Some(_) = receiver {
117+
self.error_at(Some(*name.start()), "Member functions are not implemented yet", false);
118+
}
119+
120+
let template = match self.templates.iter().find(|template| *template.name == *name.source() && template.args.len() == args.len()) {
121+
Some(template) => template,
122+
None => {
123+
self.error_at(Some(*name.start()), &format!("Unresolved function call: {}", name.source()), false);
124+
return JsonElement::Error;
125+
},
126+
};
127+
128+
let arg_count = template.args.len();
129+
130+
for i in 0..arg_count {
131+
let name = template.args[i].clone();
132+
let element = args[i].clone();
133+
134+
self.template_args.push((name, element));
135+
}
136+
137+
let expr = self.compile_expr(template.expr.clone());
138+
self.template_args.truncate(self.template_args.len().saturating_sub(arg_count));
139+
140+
expr
141+
}
142+
143+
pub fn had_error(&self) -> bool {
144+
self.had_error
145+
}
146+
147+
fn error_at(&mut self, pos: Option<TokenPos>, message: &str, panic: bool) {
148+
Self::error_at_impl(&mut self.had_error, &mut self.panic_mode, pos, message, panic);
149+
}
150+
151+
fn error_at_impl(had_error: &mut bool, panic_mode: &mut bool, pos: Option<TokenPos>, message: &str, panic: bool) {
152+
if *panic_mode {
153+
return;
154+
} else if panic {
155+
*panic_mode = true;
156+
}
157+
158+
if let Some(pos) = pos {
159+
eprint!("{} Error: ", pos);
160+
} else {
161+
eprint!("Error': ");
162+
}
163+
164+
eprintln!("{}", message);
165+
*had_error = true;
166+
}
167+
}

src/compiler/lexer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl TokenPos {
1414
}
1515

1616
pub fn begin() -> TokenPos {
17-
TokenPos::new(0, 0)
17+
TokenPos::new(1, 1)
1818
}
1919
}
2020

@@ -31,6 +31,7 @@ pub enum TokenType {
3131

3232
ParenthesisLeft, ParenthesisRight,
3333
BracketLeft, BracketRight,
34+
SquareBracketLeft, SquareBracketRight,
3435
Dot, Comma, Semicolon, Colon,
3536

3637
Assign, Equal,
@@ -52,6 +53,7 @@ pub enum TokenType {
5253

5354
// Keywords
5455
Inline,
56+
Template,
5557
Function,
5658

5759
// EOF
@@ -195,6 +197,8 @@ impl<'source> Lexer<'source> {
195197
')' => Ok(self.make_token(TokenType::ParenthesisRight)),
196198
'{' => Ok(self.make_token(TokenType::BracketLeft)),
197199
'}' => Ok(self.make_token(TokenType::BracketRight)),
200+
'[' => Ok(self.make_token(TokenType::SquareBracketLeft)),
201+
']' => Ok(self.make_token(TokenType::SquareBracketRight)),
198202
'.' => Ok(self.make_token(TokenType::Dot)),
199203
',' => Ok(self.make_token(TokenType::Comma)),
200204
';' => Ok(self.make_token(TokenType::Semicolon)),
@@ -311,6 +315,7 @@ impl<'source> Lexer<'source> {
311315
let token_type = match chars.next().expect("Internal compiler error: Empty identifier") {
312316
'f' => Lexer::check_keyword(name, 1, "function", TokenType::Function),
313317
'i' => Lexer::check_keyword(name, 1, "inline", TokenType::Inline),
318+
't' => Lexer::check_keyword(name, 1, "template", TokenType::Template),
314319
_ => TokenType::Identifier,
315320
};
316321

src/compiler/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
pub mod ast;
22
pub mod lexer;
33
pub mod parser;
4+
pub mod compiler;
5+
pub mod writer;

0 commit comments

Comments
 (0)