Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"

[dependencies]
tracy-client = { version = "0.17.3", default-features = false } # for tracy v0.11.1
nu-protocol = "*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's better to use a labeled version and bump manually to avoid sudden CI breakages.


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

[[bench]]
name = "benchmarks"
Expand Down
187 changes: 187 additions & 0 deletions src/ir_generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
use crate::compiler::Compiler;
use crate::errors::{Severity, SourceError};
use crate::parser::{AstNode, NodeId};
use nu_protocol::ast::{Math, Operator};
use nu_protocol::ir::{Instruction, IrBlock, Literal};
use nu_protocol::{RegId, Span};
use std::collections::HashMap;
use std::sync::Arc;

/// Generates IR (Intermediate Representation) from nu AST.
pub struct IrGenerator<'a> {
// Immutable reference to a compiler after the typechecker pass
compiler: &'a Compiler,
block: IrBlock,
errors: Vec<SourceError>,
}

impl<'a> IrGenerator<'a> {
pub fn new(compiler: &'a Compiler) -> Self {
Self {
compiler,
block: IrBlock {
instructions: vec![],
spans: vec![],
data: Arc::new([]),
ast: vec![],
comments: vec![],
register_count: 0,
file_count: 0,
},
errors: vec![],
}
}

/// Generates the IR from the given state of the compiler.
/// After this is called, use `block` and `errors` to get the result.
pub fn generate(&mut self) {
let mut instructions = vec![];
let mut next_free_reg = RegId::new(0);
let mut last_reg = RegId::new(0);
let mut node_to_reg: HashMap<NodeId, RegId> = HashMap::new();
for (i, ast_node) in self.compiler.ast_nodes.iter().enumerate() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this start from the top-level block, like Resolver or Typechecker?

match ast_node {
AstNode::Plus | AstNode::Multiply => {}
AstNode::Int => {
let val = match std::str::from_utf8(self.compiler.get_span_contents(NodeId(i)))
{
Ok(val) => val,
Err(err) => {
self.error(
format!("failed to convert a node to string: {err}"),
NodeId(i),
);
return;
}
};
let val = match val.parse::<i64>() {
Ok(val) => val,
Err(err) => {
self.error(
format!("failed to convert a node to string: {err}"),
NodeId(i),
);
return;
}
};
instructions.push(Instruction::LoadLiteral {
dst: next_free_reg,
lit: Literal::Int(val),
});
eprintln!("{} => {}", i, next_free_reg);
node_to_reg.insert(NodeId(i), next_free_reg);
next_free_reg = RegId::new(next_free_reg.get() + 1);
}
AstNode::BinaryOp { lhs, op, rhs } => {
let l = match node_to_reg.get(lhs) {
Some(l) => l,
None => {
self.error("failed to find register for given node".to_string(), *lhs);
return;
}
};
let r = match node_to_reg.get(rhs) {
Some(r) => r,
None => {
self.error("failed to find register for given node".to_string(), *lhs);
return;
}
};
let o = match self.node_to_operator(*op) {
Ok(o) => o,
Err(e) => {
self.errors.push(e);
return;
}
};
instructions.push(Instruction::BinaryOp {
lhs_dst: *l,
op: o,
rhs: *r,
});
last_reg = *l;
node_to_reg.insert(NodeId(i), *l);
}
_ => {
self.error(format!("node {:?} not suported yet", ast_node), NodeId(i));
}
}
}

instructions.push(Instruction::Return { src: last_reg });

let mut spans = vec![];
let mut ast = vec![];
for _ in 0..instructions.len() {
spans.push(Span { start: 0, end: 0 });
ast.push(None);
}
self.block = IrBlock {
instructions,
spans,
data: Arc::new([]),
ast,
comments: Vec::new(),
register_count: next_free_reg.get(),
file_count: 0,
};
}

/// Returns generated IR block.
///
/// Call `generate` before using this method and ensure there are no errors.
pub fn block(self) -> IrBlock {
self.block
}

/// Returns errors encountered during IR generation step.
///
/// Call `generate` before using this method.
pub fn errors(&self) -> &Vec<SourceError> {
&self.errors
}

/// Displays the state of the IR generator.
/// The output can be used for human debugging and for snapshot tests.
pub fn display_state(&self) -> String {
let mut result = String::new();
result.push_str("==== IR ====\n");
result.push_str(&format!("register_count: {}\n", self.block.register_count));
result.push_str(&format!("file_count: {}\n", self.block.register_count));

for (idx, instruction) in self.block.instructions.iter().enumerate() {
result.push_str(&format!("{}: {:?}\n", idx, instruction));
}

if !self.errors.is_empty() {
result.push_str("==== IR ERRORS ====\n");
for error in &self.errors {
result.push_str(&format!(
"{:?} (NodeId {}): {}\n",
error.severity, error.node_id.0, error.message
));
}
}
result
}

fn node_to_operator(&self, node_id: NodeId) -> Result<Operator, SourceError> {
match self.compiler.get_node(node_id) {
AstNode::Plus => Ok(Operator::Math(Math::Plus)),
AstNode::Multiply => Ok(Operator::Math(Math::Multiply)),
node => Err(SourceError {
message: format!("unrecognized operator {:?}", node),
node_id,
severity: Severity::Error,
}),
}
}

fn error(&mut self, message: impl Into<String>, node_id: NodeId) {
self.errors.push(SourceError {
message: message.into(),
node_id,
severity: Severity::Error,
});
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod compiler;
pub mod errors;
pub mod ir_generator;
pub mod naming;
pub mod parser;
pub mod protocol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,9 @@ snapshot_kind: text
19: bool
20: bool
21: bool
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 1): node Equal not suported yet
Error (NodeId 1): unrecognized operator Equal
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ snapshot_kind: text
Error (NodeId 1): type mismatch: unsupported addition between string and float
Error (NodeId 5): type mismatch: unsupported append between string and float
Error (NodeId 9): type mismatch: unsupported logical operation between bool and string
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node String not suported yet
Error (NodeId 2): node Float not suported yet
Error (NodeId 0): failed to find register for given node
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,10 @@ snapshot_kind: text
41: list<list<float>>
42: list<list<number>>
43: list<list<number>>
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 1): node Equal not suported yet
Error (NodeId 2): node Float not suported yet
Error (NodeId 0): failed to find register for given node
33 changes: 33 additions & 0 deletions src/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,36 @@ snapshot_kind: text
34: int
35: any
36: any
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node Name not suported yet
Error (NodeId 1): node Name not suported yet
Error (NodeId 2): node String not suported yet
Error (NodeId 7): node Call { parts: [NodeId(0), NodeId(1), NodeId(2), NodeId(6)] } not suported yet
Error (NodeId 8): node Name not suported yet
Error (NodeId 9): node Name not suported yet
Error (NodeId 10): node Name not suported yet
Error (NodeId 11): node Type { name: NodeId(10), params: None, optional: false } not suported yet
Error (NodeId 12): node Param { name: NodeId(9), ty: Some(NodeId(11)) } not suported yet
Error (NodeId 13): node Name not suported yet
Error (NodeId 14): node Name not suported yet
Error (NodeId 15): node Type { name: NodeId(14), params: None, optional: false } not suported yet
Error (NodeId 16): node Param { name: NodeId(13), ty: Some(NodeId(15)) } not suported yet
Error (NodeId 17): node Name not suported yet
Error (NodeId 18): node Name not suported yet
Error (NodeId 19): node Type { name: NodeId(18), params: None, optional: false } not suported yet
Error (NodeId 20): node Param { name: NodeId(17), ty: Some(NodeId(19)) } not suported yet
Error (NodeId 21): node Params([NodeId(12), NodeId(16), NodeId(20)]) not suported yet
Error (NodeId 22): node Variable not suported yet
Error (NodeId 23): node Variable not suported yet
Error (NodeId 24): node Variable not suported yet
Error (NodeId 25): node List([NodeId(22), NodeId(23), NodeId(24)]) not suported yet
Error (NodeId 26): node Block(BlockId(0)) not suported yet
Error (NodeId 27): node Def { name: NodeId(8), params: NodeId(21), return_ty: None, block: NodeId(26) } not suported yet
Error (NodeId 28): node Name not suported yet
Error (NodeId 29): node Name not suported yet
Error (NodeId 30): node String not suported yet
Error (NodeId 32): node String not suported yet
Error (NodeId 30): failed to find register for given node
18 changes: 18 additions & 0 deletions src/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,21 @@ snapshot_kind: text
21: closure
22: stream<binary>
23: stream<binary>
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node Variable not suported yet
Error (NodeId 1): node Name not suported yet
Error (NodeId 2): node Name not suported yet
Error (NodeId 3): node Type { name: NodeId(2), params: None, optional: false } not suported yet
Error (NodeId 4): node Param { name: NodeId(1), ty: Some(NodeId(3)) } not suported yet
Error (NodeId 5): node Name not suported yet
Error (NodeId 6): node Name not suported yet
Error (NodeId 7): node Type { name: NodeId(6), params: None, optional: false } not suported yet
Error (NodeId 8): node Param { name: NodeId(5), ty: Some(NodeId(7)) } not suported yet
Error (NodeId 9): node Params([NodeId(4), NodeId(8)]) not suported yet
Error (NodeId 10): node Variable not suported yet
Error (NodeId 12): node Variable not suported yet
Error (NodeId 13): node LessThan not suported yet
Error (NodeId 10): failed to find register for given node
30 changes: 30 additions & 0 deletions src/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,33 @@ snapshot_kind: text
22: list<any>
23: ()
24: ()
==== IR ====
register_count: 0
file_count: 0
0: Return { src: RegId(0) }
==== IR ERRORS ====
Error (NodeId 0): node Name not suported yet
Error (NodeId 1): node Name not suported yet
Error (NodeId 2): node Param { name: NodeId(1), ty: None } not suported yet
Error (NodeId 3): node Name not suported yet
Error (NodeId 4): node Name not suported yet
Error (NodeId 5): node Type { name: NodeId(4), params: None, optional: false } not suported yet
Error (NodeId 6): node Param { name: NodeId(3), ty: Some(NodeId(5)) } not suported yet
Error (NodeId 7): node Name not suported yet
Error (NodeId 8): node Name not suported yet
Error (NodeId 9): node Name not suported yet
Error (NodeId 10): node Name not suported yet
Error (NodeId 11): node Type { name: NodeId(10), params: None, optional: false } not suported yet
Error (NodeId 12): node Params([NodeId(11)]) not suported yet
Error (NodeId 13): node Type { name: NodeId(9), params: Some(NodeId(12)), optional: false } not suported yet
Error (NodeId 14): node Params([NodeId(13)]) not suported yet
Error (NodeId 15): node Type { name: NodeId(8), params: Some(NodeId(14)), optional: false } not suported yet
Error (NodeId 16): node Param { name: NodeId(7), ty: Some(NodeId(15)) } not suported yet
Error (NodeId 17): node Params([NodeId(2), NodeId(6), NodeId(16)]) not suported yet
Error (NodeId 18): node Variable not suported yet
Error (NodeId 19): node Variable not suported yet
Error (NodeId 20): node Variable not suported yet
Error (NodeId 21): node List([NodeId(18), NodeId(19), NodeId(20)]) not suported yet
Error (NodeId 22): node Block(BlockId(0)) not suported yet
Error (NodeId 23): node Def { name: NodeId(0), params: NodeId(17), return_ty: None, block: NodeId(22) } not suported yet
Error (NodeId 24): node Block(BlockId(1)) not suported yet
13 changes: 13 additions & 0 deletions src/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,16 @@ snapshot_kind: text
29: ()
30: ()
31: ()
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node Variable not suported yet
Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet
Error (NodeId 3): node Variable not suported yet
Error (NodeId 7): node List([NodeId(4), NodeId(5), NodeId(6)]) not suported yet
Error (NodeId 8): node Variable not suported yet
Error (NodeId 9): node Assignment not suported yet
Error (NodeId 10): node Variable not suported yet
Error (NodeId 12): node Variable not suported yet
Error (NodeId 10): failed to find register for given node
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,14 @@ snapshot_kind: text
==== TYPE ERRORS ====
Error (NodeId 12): unsupported ast node 'Break' in typechecker
Error (NodeId 19): unsupported ast node 'Continue' in typechecker
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node Variable not suported yet
Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: true } not suported yet
Error (NodeId 3): node Variable not suported yet
Error (NodeId 7): node List([NodeId(4), NodeId(5), NodeId(6)]) not suported yet
Error (NodeId 8): node Variable not suported yet
Error (NodeId 9): node GreaterThan not suported yet
Error (NodeId 8): failed to find register for given node
9 changes: 9 additions & 0 deletions src/snapshots/new_nu_parser__test__node_output@if_.nu.snap
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ snapshot_kind: text
17: int
18: int
19: int
==== IR ====
register_count: 0
file_count: 0
==== IR ERRORS ====
Error (NodeId 0): node Variable not suported yet
Error (NodeId 2): node Let { variable_name: NodeId(0), ty: None, initializer: NodeId(1), is_mutable: false } not suported yet
Error (NodeId 3): node Variable not suported yet
Error (NodeId 4): node LessThan not suported yet
Error (NodeId 3): failed to find register for given node
12 changes: 12 additions & 0 deletions src/snapshots/new_nu_parser__test__node_output@invalid_if.nu.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@ snapshot_kind: text
6: error
==== TYPE ERRORS ====
Error (NodeId 0): The condition for if branch is not a boolean
==== IR ====
register_count: 3
file_count: 3
0: LoadLiteral { dst: RegId(0), lit: Int(1) }
1: LoadLiteral { dst: RegId(1), lit: Int(4) }
2: LoadLiteral { dst: RegId(2), lit: Int(3) }
3: Return { src: RegId(0) }
==== IR ERRORS ====
Error (NodeId 2): node Block(BlockId(0)) not suported yet
Error (NodeId 4): node Block(BlockId(1)) not suported yet
Error (NodeId 5): node If { condition: NodeId(0), then_block: NodeId(2), else_block: Some(NodeId(4)) } not suported yet
Error (NodeId 6): node Block(BlockId(2)) not suported yet
Loading