Skip to content

Commit

Permalink
Initial Fuel HLL (FuelLabs#2)
Browse files Browse the repository at this point in the history
* initial parsing work

* parse trait declarations

* import statements

* clean lexer tree; support method calls

* basic ast skeleton beginnings

* begin ast work

* checkpoint while i swap computers

* more ast parsing

* more ast parsing

* ast: function appl, func decl, var exp

* ast: literals

* add compiler binary with nice error messages

* ast: return statements, use statements

* fix error message

* ast: traits

* more friendly parse error messages

* old email

* semicolons!

* byte literals; fix tests

* parse binary and hex literals for byte and bytes32

* refactor expression parsing

* parse array exprs

* parse operator expressions

* type ascriptions

* parser: polymorphism and trait bounds

* default to u64 instead of u32

* begin work on match statements

* parse structs

* refactor

* a few program examples; parse match statements

* lex struct expressions

* parse to AST struct expressions

* compile warnings!

* assert_or_warn macro

* generic struct parameters

* parse contract/script/predicate

* improve top level failure error message

* s/ast/parse_tree

* enums

* begin semantic analysis

* begin work on type checking, inferencing, and semantics checking (FuelLabs#11)

* begin work on type checking, inferencing, and semantics checking

* fmt

* WIP; laptop dying

* match branch types

* wip type code blocks

* build failure

* operator parsing; no precedence

* compile fn

* run compile instead of parse from hllc

* begin trait declarations in ast

* return statements in AST

* allow code blocks

* handle implicit returns in code blocks

* type checking is taking shape

* generic type checking

* return multiple errors

* proper operator precedence

* add fn params to namespace when typechecking

* contextual error messages

* remove todo panics

* toml update

* small error msg tweak

* Refactor error and warning handling (FuelLabs#12)

* begin refactor of error/warnings

* finish refactor

* type check predicates

* limit number of script main functions

* parse generic types for traits

* grammar for reassignments and while loops

* variable reassignments; while loops

* check generic type params in function declarations

* fix tests

* grammar for inline asm

* Asm expressions (FuelLabs#13)

* begin implementing asm expressions

* WIP asm parsing

* fix up spans; unused value warning

* progress on trait impl

* impl traits

* big refactor

* fix asm op parsing error

* parsing for method applications

* struct expressions and declarations: type inference

* WIP subfield exprs

* subfield expressions

* baaasic method invocations

* impl self; better struct declarations

* begin package manager work

* begin work on package manager

* WIP checkpoint

* forc build MVP implemenation

* dependency resolution v1

* Namespace refactor (FuelLabs#22)

* begin namespace refactor

* move all hashmaps to namespace type

* compiles imported dependencies

* method not found error

* resolve some warnings

* fix Self type in trait implementations

* fix all warnings

* fix todo error messages

* introduce differentiation between generic and struct types

* refactor struct expression typing to use declarations

* fix lack of self type in trait implementation

* refactor typed expressions

* fix impl self namespace bug

* fix implicit return typechecking bug

* re-introduce function applications

* type check function return statements

* remove hllc

* fix only last expr having type annotation; if branch enforcement of having an else

* Control flow analysis + more (FuelLabs#28)

* begin documentation of control flow analysis algorithm

* begin graph construction

* begin graph construction

* generate graphs; further control flow work

* some improvements in control flow; still need to wire up imports into the control flow graph

* control flow graph improvements

* fix up implicit return printing in control flow graph

* organize graph code

* find dead code

* unreachable code warnings

* parse unit type as type info

* start enum expressions

* fix enum lookup bug

* type check all enum instantiations

* Resolved types (FuelLabs#29)

* begin swappnig over to resolved types

* progress in refactore

* progress on converting types

* progress in switching to resolved types

* progress in switching to resolved types

* finalize refactor to resolved types

* remove unused type variants

* fix tests

* enum variant construction code analysis

* resolve warnings

* missing enum instantiator error

* trait declarations control flow

* fix trait type mismatch error message

* individual method dead code warnings

* fix method call bug

* respect public visibility modifiers; control flow analysis on libraries

* add public traits

* move ident file

* begin analysis on return paths

* refactor of files

* begin work on analyzing return paths

* basic return path graph construction done

* documentation

* Return path analysis (FuelLabs#30)

* begin analysis on return paths

* refactor of files

* begin work on analyzing return paths

* basic return path graph construction done

* documentation

* fix code block type parsing

* control flow analysis on if and code blocks

* struct fields in graph

* individual struct field warnings

* add line_col method for errors and warnings

* Generate Assembly (FuelLabs#31)

* begin generating assembly

* add unique registers counter to asm expressions

* sketch out asm generation with todo! macros everywhere

* begin while loop assembly

* rework compile fn for asm

* have to commit to save my progress as i boot into windows for fortnite

* make progress in expression generation

* WIP: return statements

* asm expressions and asm refactor

* very basic bytecode compilation

* first asm!

* ASM: While loops and reassignments

* remove subsequent jumps

* reuse data section values for duplicate literals

* struct expressions

* fix SW order

* stashing checkpoint

* forgotten add

* asm for enum instantiations

* if expression assembly generation

* code block asm generation

* remove TODO in code analysis

* remove some panics

* remove a bunch of todo panics

Co-authored-by: Alexander Hansen <[email protected]>

* move license; clean warnings

* Update forc/src/cli/build.rs

Co-authored-by: John Adler <[email protected]>

* Update forc/src/cli/build.rs

Co-authored-by: John Adler <[email protected]>

* code review feedback

* Update forc/src/manifest.rs

Co-authored-by: John Adler <[email protected]>

* Update parser/src/control_flow_analysis/analyze_return_paths.rs

Co-authored-by: John Adler <[email protected]>

* more PR feedback

* rename parser to core_lang

* add minimum supported version

* Update README.md

Co-authored-by: John Adler <[email protected]>

* check that struct size in words fits in a u32 gracefully

* forgotten import

Co-authored-by: Alexander Hansen <[email protected]>
Co-authored-by: John Adler <[email protected]>
  • Loading branch information
3 people authored May 8, 2021
1 parent c887c4a commit 18ac205
Show file tree
Hide file tree
Showing 81 changed files with 13,255 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Generated by Cargo
# will have compiled files and executables
/target/
**/*/target/
target

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Expand Down
10 changes: 2 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
[package]
name = "hll"
version = "0.1.0"
authors = ["Alex <[email protected]>"]
edition = "2018"
[workspace]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
members = ["core_lang", "forc"]
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
# fuel-vm-hll
High Level Language (Name Subject to Change) for the FuelVM
# Fume

Fume is a language developed for the Fuel blockchain. It is heavily inspired by Rust and aims to bring modern language development and performance to the blockchain ecosystem.

## Running the Compiler
To run the compiler from this directory:
```
cargo run --bin forc -- -p <path_to_project>
// e.g.
cargo run --bin forc -- build -p example_project/fuel_project
```

17 changes: 17 additions & 0 deletions core_lang/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "core_lang"
version = "0.1.0"
authors = ["Alex <[email protected]>"]
edition = "2018"
rust = "1.50"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
pest = "2.0"
pest_derive = "2.0"
thiserror = "1.0"
either = "1.6"
Inflector = "0.11"
petgraph = "0.5"
uuid-b64 = "0.1"
8 changes: 8 additions & 0 deletions core_lang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# fuel-vm-hll
High Level Language (Name Subject to Change) for the FuelVM.

# Running the Compiler
It is recommended to run this compiler from the `forc` executable, which can be found in this workspace.

# Minimum supported Rust version
As of now, this code was developed on and is guaranteed to run on Rust 1.50 stable.
1 change: 1 addition & 0 deletions core_lang/src/asm_generation/compiler_constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

15 changes: 15 additions & 0 deletions core_lang/src/asm_generation/declaration/fn_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::{
asm_generation::{AsmNamespace, RegisterSequencer},
asm_lang::Op,
error::*,
TypedFunctionDeclaration,
};

pub(crate) fn convert_fn_decl_to_asm<'sc>(
_decl: &TypedFunctionDeclaration<'sc>,
_namespace: &mut AsmNamespace,
_register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
// for now, we inline all functions as a shortcut.
ok(vec![], vec![], vec![])
}
42 changes: 42 additions & 0 deletions core_lang/src/asm_generation/declaration/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::{asm_lang::Op, error::*, TypedDeclaration};

use super::{AsmNamespace, RegisterSequencer};
mod fn_decl;
mod reassignment;
mod var_decl;
pub(crate) use fn_decl::convert_fn_decl_to_asm;
pub(crate) use reassignment::convert_reassignment_to_asm;
pub(crate) use var_decl::convert_variable_decl_to_asm;

pub(crate) fn convert_decl_to_asm<'sc>(
decl: &TypedDeclaration<'sc>,
namespace: &mut AsmNamespace<'sc>,
register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
match decl {
// For an enum declaration, we don't generate any asm.
TypedDeclaration::EnumDeclaration(_) => ok(vec![], vec![], vec![]),
TypedDeclaration::FunctionDeclaration(typed_fn_decl) => {
convert_fn_decl_to_asm(typed_fn_decl, namespace, register_sequencer)
}
// a trait declaration also does not have any asm directly generated from it
TypedDeclaration::TraitDeclaration(_) => ok(vec![], vec![], vec![]),
// since all functions are inlined (for now -- shortcut), we also don't need to do anything for this.
TypedDeclaration::ImplTrait { .. } => ok(vec![], vec![], vec![]),
// once again the declaration of a type has no inherent asm, only instantiations
TypedDeclaration::StructDeclaration(_) => ok(vec![], vec![], vec![]),
TypedDeclaration::VariableDeclaration(var_decl) => {
convert_variable_decl_to_asm(var_decl, namespace, register_sequencer)
}
TypedDeclaration::Reassignment(reassignment) => {
convert_reassignment_to_asm(reassignment, namespace, register_sequencer)
}
_ => err(
vec![],
vec![CompileError::Unimplemented(
"ASM generation has not yet been implemented for this declaration variant.",
decl.span().clone(),
)],
),
}
}
52 changes: 52 additions & 0 deletions core_lang/src/asm_generation/declaration/reassignment.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use super::*;
use crate::{
asm_generation::{convert_expression_to_asm, AsmNamespace, RegisterSequencer},
semantics::ast_node::TypedReassignment,
};

pub(crate) fn convert_reassignment_to_asm<'sc>(
reassignment: &TypedReassignment<'sc>,
namespace: &mut AsmNamespace<'sc>,
register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
// 0. evaluate the RHS of the reassignment
// 1. Find the register that the previous var was stored in
// 2. move the return register of the RHS into the register in the namespace

let mut buf = vec![];
let mut warnings = vec![];
let mut errors = vec![];
// step 0
let return_register = register_sequencer.next();
let mut rhs = type_check!(
convert_expression_to_asm(
&reassignment.rhs,
namespace,
&return_register,
register_sequencer
),
vec![],
warnings,
errors
);

buf.append(&mut rhs);

// step 1
let var_register = type_check!(
namespace.look_up_variable(&reassignment.lhs),
return err(warnings, errors),
warnings,
errors
);

// step 2
buf.push(Op::register_move_comment(
var_register.clone(),
return_register,
reassignment.lhs.span.clone(),
format!("variable {} reassignment", reassignment.lhs.primary_name),
));

ok(buf, warnings, errors)
}
20 changes: 20 additions & 0 deletions core_lang/src/asm_generation/declaration/var_decl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::{
asm_generation::{convert_expression_to_asm, AsmNamespace, RegisterSequencer},
asm_lang::Op,
error::*,
semantics::ast_node::TypedVariableDeclaration,
};

/// Provisions a register to put a variable in, and then adds the assembly used to initialize the
/// variable to the end of the buffer.
pub(crate) fn convert_variable_decl_to_asm<'sc>(
var_decl: &TypedVariableDeclaration<'sc>,
namespace: &mut AsmNamespace<'sc>,
register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
let var_register = register_sequencer.next();
let initialization =
convert_expression_to_asm(&var_decl.body, namespace, &var_register, register_sequencer);
namespace.insert_variable(var_decl.name.clone(), var_register);
initialization
}
103 changes: 103 additions & 0 deletions core_lang/src/asm_generation/expression/enum_instantiation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use crate::asm_generation::{convert_expression_to_asm, AsmNamespace, RegisterSequencer};
use crate::asm_lang::{ConstantRegister, Op, Opcode, RegisterId};
use crate::error::*;
use crate::semantics::ast_node::TypedEnumDeclaration;
use crate::semantics::TypedExpression;
use crate::Literal;
use crate::{CompileResult, Ident};
use std::convert::TryFrom;

pub(crate) fn convert_enum_instantiation_to_asm<'sc>(
decl: &TypedEnumDeclaration<'sc>,
_variant_name: &Ident<'sc>,
tag: usize,
contents: &Option<Box<TypedExpression<'sc>>>,
return_register: &RegisterId,
namespace: &mut AsmNamespace<'sc>,
register_sequencer: &mut RegisterSequencer,
) -> CompileResult<'sc, Vec<Op<'sc>>> {
let mut warnings = vec![];
let mut errors = vec![];
// step 0: load the tag into a register
// step 1: load the data into a register
// step 2: write both registers sequentially to memory, extending the call frame
// step 3: write the location of the value to the return register
let mut asm_buf = vec![];
// step 0
let data_label = namespace.insert_data_value(&Literal::U64(tag as u64));
let tag_register = register_sequencer.next();
asm_buf.push(Op::unowned_load_data_comment(
tag_register.clone(),
data_label,
format!("{} enum instantiation", decl.name.primary_name),
));
let pointer_register = register_sequencer.next();
// copy stack pointer into pointer register
asm_buf.push(Op::unowned_register_move_comment(
pointer_register.clone(),
RegisterId::Constant(ConstantRegister::StackPointer),
"load $sp for enum pointer",
));
let size_of_enum = 1 /* tag */ + decl.as_type().stack_size_of();
let size_of_enum: u32 = match u32::try_from(size_of_enum) {
Ok(o) if o < 16777216 /* 2^24 */ => o,
_ => {
errors.push(CompileError::Unimplemented(
"Stack variables which exceed 2^24 (16777216) words in size are not supported yet.",
decl.clone().span,
));
return err(warnings, errors);
}
};

asm_buf.push(Op::unowned_stack_allocate_memory(size_of_enum));
// initialize all the memory to 0
asm_buf.push(Op::new(
Opcode::MemClearImmediate(pointer_register.clone(), size_of_enum),
decl.clone().span,
));
// write the tag
// step 2
asm_buf.push(Op::write_register_to_memory(
pointer_register.clone(),
tag_register.clone(),
0,
decl.clone().span,
));

// step 1 continued
// // if there are any enum contents, instantiate them
if let Some(instantiation) = contents {
let return_register = register_sequencer.next();
let mut asm = type_check!(
convert_expression_to_asm(
&*instantiation,
namespace,
&return_register.clone(),
register_sequencer
),
return err(warnings, errors),
warnings,
errors
);
asm_buf.append(&mut asm);
// write these enum contents to the address after the tag
// step 2
asm_buf.push(Op::write_register_to_memory_comment(
pointer_register.clone(),
return_register.clone(),
1, /* offset by 1 because the tag was already written */
instantiation.span.clone(),
format!("{} enum contents", decl.name.primary_name),
));
}

// step 3
asm_buf.push(Op::register_move(
return_register.clone(),
pointer_register,
decl.clone().span,
));

ok(asm_buf, warnings, errors)
}
Loading

0 comments on commit 18ac205

Please sign in to comment.