Skip to content

Commit 1ebddec

Browse files
committed
Initial generation of IR from nu AST.
The initial implementation only handles simple math expressions, the focus is primarily on introducing new structs, agreeing on naming and adding the output to insta tests.
1 parent eba4f27 commit 1ebddec

32 files changed

+602
-1
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2021"
77

88
[dependencies]
99
tracy-client = { version = "0.17.3", default-features = false } # for tracy v0.11.1
10+
nu-protocol = "*"
1011

1112
[profile.profiling]
1213
inherits = "release"
@@ -29,7 +30,6 @@ path = "src/lib.rs"
2930
insta = { version = "1.33.0", features = ["glob"] }
3031
tango-bench = "0.6"
3132
nu-parser = "0.99"
32-
nu-protocol = "0.99"
3333

3434
[[bench]]
3535
name = "benchmarks"

src/ir_generator.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
use crate::compiler::Compiler;
2+
use crate::errors::{Severity, SourceError};
3+
use crate::parser::{AstNode, NodeId};
4+
use nu_protocol::ast::{Math, Operator};
5+
use nu_protocol::ir::{Instruction, IrBlock, Literal};
6+
use nu_protocol::{RegId, Span};
7+
use std::collections::HashMap;
8+
use std::sync::Arc;
9+
10+
/// Generates IR (Intermediate Representation) from nu AST.
11+
pub struct IrGenerator<'a> {
12+
// Immutable reference to a compiler after the typechecker pass
13+
compiler: &'a Compiler,
14+
block: IrBlock,
15+
errors: Vec<SourceError>,
16+
}
17+
18+
impl<'a> IrGenerator<'a> {
19+
pub fn new(compiler: &'a Compiler) -> Self {
20+
Self {
21+
compiler,
22+
block: IrBlock {
23+
instructions: vec![],
24+
spans: vec![],
25+
data: Arc::new([]),
26+
ast: vec![],
27+
comments: vec![],
28+
register_count: 0,
29+
file_count: 0,
30+
},
31+
errors: vec![],
32+
}
33+
}
34+
35+
/// Generates the IR from the given state of the compiler.
36+
/// After this is called, use `block` and `errors` to get the result.
37+
pub fn generate(&mut self) {
38+
let mut instructions = vec![];
39+
let mut next_free_reg = RegId::new(0);
40+
let mut last_reg = RegId::new(0);
41+
let mut node_to_reg: HashMap<NodeId, RegId> = HashMap::new();
42+
for (i, ast_node) in self.compiler.ast_nodes.iter().enumerate() {
43+
match ast_node {
44+
AstNode::Plus | AstNode::Multiply => {}
45+
AstNode::Int => {
46+
let val = match std::str::from_utf8(self.compiler.get_span_contents(NodeId(i)))
47+
{
48+
Ok(val) => val,
49+
Err(err) => {
50+
self.error(
51+
format!("failed to convert a node to string: {err}"),
52+
NodeId(i),
53+
);
54+
return;
55+
}
56+
};
57+
let val = match val.parse::<i64>() {
58+
Ok(val) => val,
59+
Err(err) => {
60+
self.error(
61+
format!("failed to convert a node to string: {err}"),
62+
NodeId(i),
63+
);
64+
return;
65+
}
66+
};
67+
instructions.push(Instruction::LoadLiteral {
68+
dst: next_free_reg,
69+
lit: Literal::Int(val),
70+
});
71+
eprintln!("{} => {}", i, next_free_reg);
72+
node_to_reg.insert(NodeId(i), next_free_reg);
73+
next_free_reg = RegId::new(next_free_reg.get() + 1);
74+
}
75+
AstNode::BinaryOp { lhs, op, rhs } => {
76+
let l = match node_to_reg.get(lhs) {
77+
Some(l) => l,
78+
None => {
79+
self.error("failed to find register for given node".to_string(), *lhs);
80+
return;
81+
}
82+
};
83+
let r = match node_to_reg.get(rhs) {
84+
Some(r) => r,
85+
None => {
86+
self.error("failed to find register for given node".to_string(), *lhs);
87+
return;
88+
}
89+
};
90+
let o = match self.node_to_operator(*op) {
91+
Ok(o) => o,
92+
Err(e) => {
93+
self.errors.push(e);
94+
return;
95+
}
96+
};
97+
instructions.push(Instruction::BinaryOp {
98+
lhs_dst: *l,
99+
op: o,
100+
rhs: *r,
101+
});
102+
last_reg = *l;
103+
node_to_reg.insert(NodeId(i), *l);
104+
}
105+
_ => {
106+
self.error(format!("node {:?} not suported yet", ast_node), NodeId(i));
107+
}
108+
}
109+
}
110+
111+
instructions.push(Instruction::Return { src: last_reg });
112+
113+
let mut spans = vec![];
114+
let mut ast = vec![];
115+
for _ in 0..instructions.len() {
116+
spans.push(Span { start: 0, end: 0 });
117+
ast.push(None);
118+
}
119+
self.block = IrBlock {
120+
instructions,
121+
spans,
122+
data: Arc::new([]),
123+
ast,
124+
comments: Vec::new(),
125+
register_count: next_free_reg.get(),
126+
file_count: 0,
127+
};
128+
}
129+
130+
/// Returns generated IR block.
131+
///
132+
/// Call `generate` before using this method and ensure there are no errors.
133+
pub fn block(self) -> IrBlock {
134+
self.block
135+
}
136+
137+
/// Returns errors encountered during IR generation step.
138+
///
139+
/// Call `generate` before using this method.
140+
pub fn errors(&self) -> &Vec<SourceError> {
141+
&self.errors
142+
}
143+
144+
/// Displays the state of the IR generator.
145+
/// The output can be used for human debugging and for snapshot tests.
146+
pub fn display_state(&self) -> String {
147+
let mut result = String::new();
148+
result.push_str("==== IR ====\n");
149+
result.push_str(&format!("register_count: {}\n", self.block.register_count));
150+
result.push_str(&format!("file_count: {}\n", self.block.register_count));
151+
152+
for (idx, instruction) in self.block.instructions.iter().enumerate() {
153+
result.push_str(&format!("{}: {:?}\n", idx, instruction));
154+
}
155+
156+
if !self.errors.is_empty() {
157+
result.push_str("==== IR ERRORS ====\n");
158+
for error in &self.errors {
159+
result.push_str(&format!(
160+
"{:?} (NodeId {}): {}\n",
161+
error.severity, error.node_id.0, error.message
162+
));
163+
}
164+
}
165+
result
166+
}
167+
168+
fn node_to_operator(&self, node_id: NodeId) -> Result<Operator, SourceError> {
169+
match self.compiler.get_node(node_id) {
170+
AstNode::Plus => Ok(Operator::Math(Math::Plus)),
171+
AstNode::Multiply => Ok(Operator::Math(Math::Multiply)),
172+
node => Err(SourceError {
173+
message: format!("unrecognized operator {:?}", node),
174+
node_id,
175+
severity: Severity::Error,
176+
}),
177+
}
178+
}
179+
180+
fn error(&mut self, message: impl Into<String>, node_id: NodeId) {
181+
self.errors.push(SourceError {
182+
message: message.into(),
183+
node_id,
184+
severity: Severity::Error,
185+
});
186+
}
187+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub mod compiler;
22
pub mod errors;
3+
pub mod ir_generator;
34
pub mod naming;
45
pub mod parser;
56
pub mod protocol;

src/snapshots/new_nu_parser__test__node_output@binary_ops_exact.nu.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,9 @@ snapshot_kind: text
5252
19: bool
5353
20: bool
5454
21: bool
55+
==== IR ====
56+
register_count: 0
57+
file_count: 0
58+
==== IR ERRORS ====
59+
Error (NodeId 1): node Equal not suported yet
60+
Error (NodeId 1): unrecognized operator Equal

src/snapshots/new_nu_parser__test__node_output@binary_ops_mismatch.nu.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,10 @@ snapshot_kind: text
3838
Error (NodeId 1): type mismatch: unsupported addition between string and float
3939
Error (NodeId 5): type mismatch: unsupported append between string and float
4040
Error (NodeId 9): type mismatch: unsupported logical operation between bool and string
41+
==== IR ====
42+
register_count: 0
43+
file_count: 0
44+
==== IR ERRORS ====
45+
Error (NodeId 0): node String not suported yet
46+
Error (NodeId 2): node Float not suported yet
47+
Error (NodeId 0): failed to find register for given node

src/snapshots/new_nu_parser__test__node_output@binary_ops_subtypes.nu.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,10 @@ snapshot_kind: text
9696
41: list<list<float>>
9797
42: list<list<number>>
9898
43: list<list<number>>
99+
==== IR ====
100+
register_count: 0
101+
file_count: 0
102+
==== IR ERRORS ====
103+
Error (NodeId 1): node Equal not suported yet
104+
Error (NodeId 2): node Float not suported yet
105+
Error (NodeId 0): failed to find register for given node

src/snapshots/[email protected]

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,36 @@ snapshot_kind: text
8585
34: int
8686
35: any
8787
36: any
88+
==== IR ====
89+
register_count: 0
90+
file_count: 0
91+
==== IR ERRORS ====
92+
Error (NodeId 0): node Name not suported yet
93+
Error (NodeId 1): node Name not suported yet
94+
Error (NodeId 2): node String not suported yet
95+
Error (NodeId 7): node Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] } not suported yet
96+
Error (NodeId 8): node Name not suported yet
97+
Error (NodeId 9): node Name not suported yet
98+
Error (NodeId 10): node Name not suported yet
99+
Error (NodeId 11): node Type { name: NodeId(10), params: None, optional: false } not suported yet
100+
Error (NodeId 12): node Param { name: NodeId(9), ty: Some(NodeId(11)) } not suported yet
101+
Error (NodeId 13): node Name not suported yet
102+
Error (NodeId 14): node Name not suported yet
103+
Error (NodeId 15): node Type { name: NodeId(14), params: None, optional: false } not suported yet
104+
Error (NodeId 16): node Param { name: NodeId(13), ty: Some(NodeId(15)) } not suported yet
105+
Error (NodeId 17): node Name not suported yet
106+
Error (NodeId 18): node Name not suported yet
107+
Error (NodeId 19): node Type { name: NodeId(18), params: None, optional: false } not suported yet
108+
Error (NodeId 20): node Param { name: NodeId(17), ty: Some(NodeId(19)) } not suported yet
109+
Error (NodeId 21): node Params([NodeId(12), NodeId(16), NodeId(20)]) not suported yet
110+
Error (NodeId 22): node Variable not suported yet
111+
Error (NodeId 23): node Variable not suported yet
112+
Error (NodeId 24): node Variable not suported yet
113+
Error (NodeId 25): node List([NodeId(22), NodeId(23), NodeId(24)]) not suported yet
114+
Error (NodeId 26): node Block(BlockId(0)) not suported yet
115+
Error (NodeId 27): node Def { name: NodeId(8), params: NodeId(21), return_ty: None, block: NodeId(26) } not suported yet
116+
Error (NodeId 28): node Name not suported yet
117+
Error (NodeId 29): node Name not suported yet
118+
Error (NodeId 30): node String not suported yet
119+
Error (NodeId 32): node String not suported yet
120+
Error (NodeId 30): failed to find register for given node

src/snapshots/[email protected]

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,21 @@ snapshot_kind: text
5959
21: closure
6060
22: stream<binary>
6161
23: stream<binary>
62+
==== IR ====
63+
register_count: 0
64+
file_count: 0
65+
==== IR ERRORS ====
66+
Error (NodeId 0): node Variable not suported yet
67+
Error (NodeId 1): node Name not suported yet
68+
Error (NodeId 2): node Name not suported yet
69+
Error (NodeId 3): node Type { name: NodeId(2), params: None, optional: false } not suported yet
70+
Error (NodeId 4): node Param { name: NodeId(1), ty: Some(NodeId(3)) } not suported yet
71+
Error (NodeId 5): node Name not suported yet
72+
Error (NodeId 6): node Name not suported yet
73+
Error (NodeId 7): node Type { name: NodeId(6), params: None, optional: false } not suported yet
74+
Error (NodeId 8): node Param { name: NodeId(5), ty: Some(NodeId(7)) } not suported yet
75+
Error (NodeId 9): node Params([NodeId(4), NodeId(8)]) not suported yet
76+
Error (NodeId 10): node Variable not suported yet
77+
Error (NodeId 12): node Variable not suported yet
78+
Error (NodeId 13): node LessThan not suported yet
79+
Error (NodeId 10): failed to find register for given node

src/snapshots/[email protected]

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,33 @@ snapshot_kind: text
6161
22: list<any>
6262
23: ()
6363
24: ()
64+
==== IR ====
65+
register_count: 0
66+
file_count: 0
67+
0: Return { src: RegId(0) }
68+
==== IR ERRORS ====
69+
Error (NodeId 0): node Name not suported yet
70+
Error (NodeId 1): node Name not suported yet
71+
Error (NodeId 2): node Param { name: NodeId(1), ty: None } not suported yet
72+
Error (NodeId 3): node Name not suported yet
73+
Error (NodeId 4): node Name not suported yet
74+
Error (NodeId 5): node Type { name: NodeId(4), params: None, optional: false } not suported yet
75+
Error (NodeId 6): node Param { name: NodeId(3), ty: Some(NodeId(5)) } not suported yet
76+
Error (NodeId 7): node Name not suported yet
77+
Error (NodeId 8): node Name not suported yet
78+
Error (NodeId 9): node Name not suported yet
79+
Error (NodeId 10): node Name not suported yet
80+
Error (NodeId 11): node Type { name: NodeId(10), params: None, optional: false } not suported yet
81+
Error (NodeId 12): node Params([NodeId(11)]) not suported yet
82+
Error (NodeId 13): node Type { name: NodeId(9), params: Some(NodeId(12)), optional: false } not suported yet
83+
Error (NodeId 14): node Params([NodeId(13)]) not suported yet
84+
Error (NodeId 15): node Type { name: NodeId(8), params: Some(NodeId(14)), optional: false } not suported yet
85+
Error (NodeId 16): node Param { name: NodeId(7), ty: Some(NodeId(15)) } not suported yet
86+
Error (NodeId 17): node Params([NodeId(2), NodeId(6), NodeId(16)]) not suported yet
87+
Error (NodeId 18): node Variable not suported yet
88+
Error (NodeId 19): node Variable not suported yet
89+
Error (NodeId 20): node Variable not suported yet
90+
Error (NodeId 21): node List([NodeId(18), NodeId(19), NodeId(20)]) not suported yet
91+
Error (NodeId 22): node Block(BlockId(0)) not suported yet
92+
Error (NodeId 23): node Def { name: NodeId(0), params: NodeId(17), return_ty: None, block: NodeId(22) } not suported yet
93+
Error (NodeId 24): node Block(BlockId(1)) not suported yet

src/snapshots/[email protected]

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,16 @@ snapshot_kind: text
7777
29: ()
7878
30: ()
7979
31: ()
80+
==== IR ====
81+
register_count: 0
82+
file_count: 0
83+
==== IR ERRORS ====
84+
Error (NodeId 0): node Variable not suported yet
85+
Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet
86+
Error (NodeId 3): node Variable not suported yet
87+
Error (NodeId 7): node List([NodeId(4), NodeId(5), NodeId(6)]) not suported yet
88+
Error (NodeId 8): node Variable not suported yet
89+
Error (NodeId 9): node Assignment not suported yet
90+
Error (NodeId 10): node Variable not suported yet
91+
Error (NodeId 12): node Variable not suported yet
92+
Error (NodeId 10): failed to find register for given node

0 commit comments

Comments
 (0)