Skip to content

Commit

Permalink
Parser support for struct declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
sbillig committed Jun 21, 2024
1 parent f5ce529 commit e06373e
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 55 deletions.
4 changes: 4 additions & 0 deletions crates/ir/src/builder/module_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ impl ModuleBuilder {
.with_ty_store_mut(|s| s.make_struct(name, fields, packed))
}

pub fn get_struct_type(&self, name: &str) -> Option<Type> {
self.ctx.with_ty_store(|s| s.struct_type_by_name(name))
}

pub fn declare_array_type(&mut self, elem: Type, len: usize) -> Type {
self.ctx.with_ty_store_mut(|s| s.make_array(elem, len))
}
Expand Down
4 changes: 2 additions & 2 deletions crates/ir/src/ir_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,9 @@ impl StructData {
}

if self.packed {
write!(w, "}}>;")
writeln!(w, "}}>;")
} else {
write!(w, "}};")
writeln!(w, "}};")
}
}
}
Expand Down
128 changes: 89 additions & 39 deletions crates/parser2/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,14 @@ pub fn parse(input: &str) -> Result<Module, Vec<Error>> {
pub struct Module {
pub target: Option<TargetTriple>,
pub declared_functions: Vec<FuncDeclaration>,
pub struct_types: Vec<Struct>,
pub functions: Vec<Func>,
pub comments: Vec<String>,
}

impl FromSyntax<Error> for Module {
fn from_syntax(node: &mut Node<Error>) -> Self {
let target = match node
.get_opt(Rule::target_triple)
.map(|p| TargetTriple::parse(p.as_str()))
{
Some(Ok(t)) => Some(t),
Some(Err(e)) => {
node.error(Error::InvalidTarget(e, node.span.clone()));
None
}
None => None,
};
let target = node.single_opt(Rule::target_triple).flatten();

let module_comments = node.map_while(|p| {
if p.as_rule() == Rule::COMMENT && p.as_str().starts_with("#!") {
Expand All @@ -72,8 +63,10 @@ impl FromSyntax<Error> for Module {
}
});

let mut struct_types = vec![];
let mut declared_functions = vec![];
let mut functions = vec![];

loop {
let comments = node.map_while(|p| {
if p.as_rule() == Rule::COMMENT {
Expand All @@ -83,7 +76,9 @@ impl FromSyntax<Error> for Module {
}
});

if let Some(func) = node.single_opt(Rule::function_declaration) {
if let Some(struct_) = node.single_opt(Rule::struct_declaration) {
struct_types.push(struct_);
} else if let Some(func) = node.single_opt(Rule::function_declaration) {
declared_functions.push(func);
} else {
match node.single_opt::<Func>(Rule::function) {
Expand All @@ -98,12 +93,88 @@ impl FromSyntax<Error> for Module {
Module {
target,
declared_functions,
struct_types,
functions,
comments: module_comments,
}
}
}

impl FromSyntax<Error> for Option<TargetTriple> {
fn from_syntax(node: &mut Node<Error>) -> Self {
match TargetTriple::parse(node.txt) {
Ok(t) => Some(t),
Err(e) => {
node.error(Error::InvalidTarget(e, node.span.clone()));
None
}
}
}
}

impl FromSyntax<Error> for SmolStr {
fn from_syntax(node: &mut Node<Error>) -> Self {
node.txt.into()
}
}

#[derive(Debug)]
pub struct FuncDeclaration {
pub linkage: Linkage,
pub name: FunctionName,
pub params: Vec<Type>,
pub ret_type: Option<Type>,
}

impl FromSyntax<Error> for FuncDeclaration {
fn from_syntax(node: &mut Node<Error>) -> Self {
let linkage = node
.parse_str_opt(Rule::function_linkage)
.unwrap_or(Linkage::Private);

FuncDeclaration {
linkage,
name: node.single(Rule::function_identifier),
params: node.descend_into(Rule::function_param_type_list, |n| n.multi(Rule::type_name)),
ret_type: node.descend_into_opt(Rule::function_ret_type, |n| n.single(Rule::type_name)),
}
}
}

#[derive(Debug)]
pub struct Struct {
pub name: StructName,
pub fields: Vec<Type>,
pub packed: bool,
}

impl FromSyntax<Error> for Struct {
fn from_syntax(node: &mut Node<Error>) -> Self {
let name = node.single(Rule::struct_identifier);
node.descend();
let (fields, packed) = match node.rule {
Rule::normal_field_list => (node.multi(Rule::type_name), false),
Rule::packed_field_list => (node.multi(Rule::type_name), true),
_ => unreachable!(),
};

Self {
name,
fields,
packed,
}
}
}

#[derive(Debug)]
pub struct StructName(pub SmolStr);

impl FromSyntax<Error> for StructName {
fn from_syntax(node: &mut Node<Error>) -> Self {
Self(node.single(Rule::struct_name))
}
}

#[derive(Debug)]
pub struct Func {
pub signature: FuncSignature,
Expand Down Expand Up @@ -144,26 +215,13 @@ impl FromSyntax<Error> for FuncSignature {
}
}

/// Doesn't include `%` prefix.
#[derive(Debug)]
pub struct FuncDeclaration {
pub linkage: Linkage,
pub name: FunctionName,
pub params: Vec<Type>,
pub ret_type: Option<Type>,
}
pub struct FunctionName(pub SmolStr);

impl FromSyntax<Error> for FuncDeclaration {
impl FromSyntax<Error> for FunctionName {
fn from_syntax(node: &mut Node<Error>) -> Self {
let linkage = node
.parse_str_opt(Rule::function_linkage)
.unwrap_or(Linkage::Private);

FuncDeclaration {
linkage,
name: node.single(Rule::function_identifier),
params: node.descend_into(Rule::function_param_type_list, |n| n.multi(Rule::type_name)),
ret_type: node.descend_into_opt(Rule::function_ret_type, |n| n.single(Rule::type_name)),
}
FunctionName(node.parse_str(Rule::function_name))
}
}

Expand Down Expand Up @@ -252,6 +310,7 @@ pub enum Type {
Int(IntType),
Ptr(Box<Type>),
Array(Box<Type>, usize),
Struct(SmolStr),
Void,
Error,
}
Expand All @@ -270,6 +329,7 @@ impl FromSyntax<Error> for Type {
Type::Array(Box::new(node.single(Rule::type_name)), size)
}
Rule::void_type => Type::Void,
Rule::struct_identifier => Type::Struct(node.parse_str(Rule::struct_name)),
_ => unreachable!(),
}
}
Expand Down Expand Up @@ -340,16 +400,6 @@ impl FromSyntax<Error> for Expr {
#[derive(Debug)]
pub struct Call(pub FunctionName, pub Vec<Value>);

/// Doesn't include `%` prefix.
#[derive(Debug)]
pub struct FunctionName(pub SmolStr);

impl FromSyntax<Error> for FunctionName {
fn from_syntax(node: &mut Node<Error>) -> Self {
FunctionName(node.parse_str(Rule::function_name))
}
}

#[derive(Debug)]
pub struct ValueName(pub SmolStr);

Expand Down
14 changes: 14 additions & 0 deletions crates/parser2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ pub fn parse_module(input: &str) -> Result<ParsedModule, Vec<Error>> {
let ctx = ModuleCtx::new(isa);
let mut builder = ModuleBuilder::new(ctx);

for st in ast.struct_types {
let fields = st
.fields
.iter()
.map(|t| build_type(&mut builder, t))
.collect::<Vec<_>>();
builder.declare_struct_type(&st.name.0, &fields, false);
}

for func in ast.declared_functions {
let params = func
.params
Expand Down Expand Up @@ -225,6 +234,11 @@ fn build_type(builder: &mut ModuleBuilder, t: &ast::Type) -> ir::Type {
builder.declare_array_type(elem, *n)
}
ast::Type::Void => ir::Type::Void,
ast::Type::Struct(name) => builder.get_struct_type(name).unwrap_or_else(|| {
// xxx error on undeclared struct
eprintln!("struct type not found: {name}");
ir::Type::Void
}),
ast::Type::Error => todo!(),
}
}
24 changes: 16 additions & 8 deletions crates/parser2/src/sonatina.pest
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
module = { SOI ~ NEWLINE* ~ target_specifier ~ (NEWLINE+ ~ function_declaration)* ~ (NEWLINE+ ~ function)* ~ NEWLINE* ~ EOI }
module = { SOI ~ NEWLINE* ~ target_specifier ~ (NEWLINE+ ~ declaration)* ~ (NEWLINE+ ~ function)* ~ NEWLINE* ~ EOI }

WHITESPACE = _{ " " | "\t" }
COMMENT = { "#" ~ (!NEWLINE ~ ANY)* }

ident_start_char = { ASCII_ALPHA | "_" }
ident_body_char = { ASCII_ALPHANUMERIC | "_" }

target_specifier = _{ "target" ~ "=" ~ "\"" ~ target_triple ~ "\"" }
target_triple = @{ ASCII_ALPHA* ~ "-" ~ ASCII_ALPHA* ~ "-" ~ ASCII_ALPHA* }

ident_start_char = { ASCII_ALPHA | "_" }
ident_body_char = { ASCII_ALPHANUMERIC | "_" }
declaration = _{ function_declaration | struct_declaration }
function_declaration = { "declare" ~ function_linkage? ~ function_identifier ~ function_param_type_list ~ function_ret_type? ~ ";" }
function_param_type_list = { "(" ~ (type_name ~ ",")* ~ type_name? ~ ")" }
struct_declaration = { "type" ~ struct_identifier ~ "=" ~ struct_fields ~ ";" }
struct_identifier = ${ "%" ~ struct_name }
struct_fields = _{ normal_field_list | packed_field_list }
normal_field_list = { "{" ~ type_list ~ "}" }
packed_field_list = { "<{" ~ type_list ~ "}>" }
type_list = _{ (type_name ~ ",")* ~ type_name? }
struct_name = @{ ident_start_char ~ ident_body_char* }

function = { function_signature ~ function_body }
_functions = _{ (NEWLINE* ~ function ~ NEWLINE*)* }
function_signature = { "func" ~ function_linkage? ~ function_identifier ~ function_params ~ function_ret_type? }
function_ret_type = { "->" ~ type_name }
function_linkage = { "public" | "private" | "external" }
function_name = @{ ident_start_char ~ ident_body_char* }
function_identifier = ${ "%" ~ function_name }
function_name = @{ ident_start_char ~ ident_body_char* }
function_params = { "(" ~ (value_declaration ~ ",")* ~ value_declaration? ~ ")" }
function_body = _{ "{" ~ (NEWLINE+ ~ block?)* ~ "}" }
block = { block_ident ~ ":" ~ (NEWLINE+ ~ stmt)* }
_stmts = _{ (stmt ~ NEWLINE+)* }

function_declaration = { "declare" ~ function_linkage? ~ function_identifier ~ function_param_type_list ~ function_ret_type? ~ ";" }
function_param_type_list = { "(" ~ (type_name ~ ",")* ~ type_name? ~ ")" }

block_ident = ${ "block" ~ block_number }
block_number = { ASCII_DIGIT+ }
value_name = ${ "v" ~ ASCII_DIGIT+ }

type_name = { primitive_type | ptr_type | array_type | void_type }
type_name = { primitive_type | ptr_type | array_type | void_type | struct_identifier }
primitive_type = { "i8" | "i16" | "i32" | "i64" | "i128" | "i256" | "i1" }
ptr_type = ${ "*" ~ type_name }
array_type = !{ "[" ~ type_name ~ ";" ~ array_size ~ "]" }
Expand Down
56 changes: 56 additions & 0 deletions crates/parser2/test_files/syntax/module/simple.ast.snap
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,44 @@ Module {
),
},
],
struct_types: [
Struct {
name: StructName(
"foo",
),
fields: [
Int(
I8,
),
Int(
I16,
),
Ptr(
Int(
I64,
),
),
],
packed: false,
},
Struct {
name: StructName(
"bar",
),
fields: [
Int(
I8,
),
Array(
Int(
I8,
),
31,
),
],
packed: true,
},
],
functions: [
Func {
signature: FuncSignature {
Expand Down Expand Up @@ -247,6 +285,24 @@ Module {
2,
),
),
ValueDeclaration(
ValueName(
"v4",
),
Struct(
"foo",
),
),
ValueDeclaration(
ValueName(
"v5",
),
Ptr(
Struct(
"foo",
),
),
),
],
ret_type: None,
},
Expand Down
4 changes: 3 additions & 1 deletion crates/parser2/test_files/syntax/module/simple.ir.snap
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ expression: w.dump_string().unwrap()
input_file: crates/parser2/test_files/syntax/module/simple.sntn
---
target = evm-ethereum-london
type %foo = {i8, i16, *i64};
type %bar = {i8, [i8; 31]};
func external %add_i8(v0.i8, v1.i8) -> i8 {
}

Expand All @@ -22,7 +24,7 @@ func private %foo(v0.i8) -> i8 {

}

func private %types(v0.*i8, v1.[i8; 2], v2.[*i8; 2], v3.[[i8; 2]; 2]) -> void {
func private %types(v0.*i8, v1.[i8; 2], v2.[*i8; 2], v3.[[i8; 2]; 2], v4.%foo, v5.*%foo) -> void {
block0:
return;

Expand Down
Loading

0 comments on commit e06373e

Please sign in to comment.