Skip to content

Commit

Permalink
Initializes primitive struct builder
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon committed Sep 18, 2023
1 parent 2f10a61 commit b460e38
Show file tree
Hide file tree
Showing 7 changed files with 232 additions and 64 deletions.
32 changes: 24 additions & 8 deletions stage0/src/ast/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,33 @@ use super::Expression;
use crate::lexer::{AttributeName, Span};

/// An attribute.
pub struct Attribute {
name: AttributeName,
args: Option<Vec<Vec<Expression>>>,
pub enum Attribute {
Pub(AttributeName),
Cfg(AttributeName, Vec<Expression>),
Ext(AttributeName, Extern),
Repr(AttributeName, Representation),
Custom(AttributeName, Option<Vec<Vec<Expression>>>),
}

impl Attribute {
pub fn new(name: AttributeName, args: Option<Vec<Vec<Expression>>>) -> Self {
Self { name, args }
}

pub fn span(&self) -> &Span {
self.name.span()
match self {
Attribute::Pub(n) => n.span(),
Attribute::Cfg(n, _) => n.span(),
Attribute::Ext(n, _) => n.span(),
Attribute::Repr(n, _) => n.span(),
Attribute::Custom(n, _) => n.span(),
}
}
}

/// Argument of `@ext`.
pub enum Extern {
C,
}

/// Argument of `@repr`
pub enum Representation {
U8,
Un,
}
175 changes: 145 additions & 30 deletions stage0/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ impl SourceFile {
}

fn parse_attrs(lex: &mut Lexer, first: AttributeName) -> Result<Vec<Attribute>, SyntaxError> {
// Parse the first attribute.
let mut attrs: Vec<Attribute> = Vec::new();

attrs.push(Self::parse_attr(lex, first)?);

// Parse the remaining if available.
loop {
let tok = match lex.next()? {
Some(v) => v,
Expand All @@ -181,22 +183,134 @@ impl SourceFile {
}
}

// Check for multiple built-in attributes.
let mut vis = false;
let mut cfg = false;
let mut ext = false;
let mut repr = false;

for a in &attrs {
match a {
Attribute::Pub(n) => {
if vis {
return Err(SyntaxError::new(
n.span().clone(),
"multiple pub attribute is not allowed",
));
} else {
vis = true;
}
}
Attribute::Cfg(n, _) => {
if cfg {
return Err(SyntaxError::new(
n.span().clone(),
"multiple cfg attribute is not allowed",
));
} else {
cfg = true;
}
}
Attribute::Ext(n, _) => {
if ext {
return Err(SyntaxError::new(
n.span().clone(),
"multiple ext attribute is not allowed",
));
} else {
ext = true;
}
}
Attribute::Repr(n, _) => {
if repr {
return Err(SyntaxError::new(
n.span().clone(),
"multiple repr attribute is not allowed",
));
} else {
repr = true;
}
}
Attribute::Custom(_, _) => {}
}
}

Ok(attrs)
}

fn parse_attr(lex: &mut Lexer, name: AttributeName) -> Result<Attribute, SyntaxError> {
let args = match lex.next()? {
Some(Token::OpenParenthesis(_)) => Some(Self::parse_args(lex)?),
Some(Token::CloseParenthesis(v)) => {
return Err(SyntaxError::new(v.span().clone(), "expect '('"));
let attr = match name.value() {
"cfg" => {
lex.next_op()?;
let arg = Self::parse_exprs(lex)?;
lex.next_cp()?;

Attribute::Cfg(name, arg)
}
_ => {
lex.undo();
None
"ext" => {
lex.next_op()?;
let ext = lex.next_ident()?;
lex.next_cp()?;

Attribute::Ext(
name,
match ext.value() {
"C" => Extern::C,
_ => return Err(SyntaxError::new(ext.span().clone(), "unknown extern")),
},
)
}
"pub" => match lex.next()? {
Some(Token::OpenParenthesis(_)) => match lex.next()? {
Some(Token::CloseParenthesis(_)) => Attribute::Pub(name),
_ => {
return Err(SyntaxError::new(
name.span().clone(),
"expect zero argument for this attribute",
));
}
},
Some(_) => {
lex.undo();
Attribute::Pub(name)
}
None => Attribute::Pub(name),
},
"repr" => {
lex.next_op()?;
let repr = lex.next_ident()?;
lex.next_cp()?;

Attribute::Repr(
name,
match repr.value() {
"u8" => Representation::U8,
"un" => Representation::Un,
_ => {
return Err(SyntaxError::new(
repr.span().clone(),
"unknown representation",
));
}
},
)
}
_ => Attribute::Custom(
name,
match lex.next()? {
Some(Token::OpenParenthesis(_)) => Some(Self::parse_args(lex)?),
Some(Token::CloseParenthesis(v)) => {
return Err(SyntaxError::new(v.span().clone(), "expect '('"));
}
_ => {
lex.undo();
None
}
},
),
};

Ok(Attribute::new(name, args))
Ok(attr)
}

fn parse_use(lex: &mut Lexer, def: UseKeyword) -> Result<Use, SyntaxError> {
Expand Down Expand Up @@ -282,51 +396,52 @@ impl SourceFile {

fn parse_struct(
lex: &mut Lexer,
attrs: Vec<Attribute>,
mut attrs: Vec<Attribute>,
def: StructKeyword,
name: Identifier,
) -> Result<Struct, SyntaxError> {
// Check if zero-sized struct. A zero-sized struct without a repr attribute is not allowed.
let tok = match lex.next()? {
Some(v) => v,
None => {
return Err(SyntaxError::new(
name.span().clone(),
"expect either ';' or '{' after struct name",
));
}
};
// Check if a primitive struct.
let mut repr = None;

match tok {
Token::Semicolon(_) => return Ok(Struct::new(attrs, def, name)),
Token::OpenCurly(_) => {}
v => {
return Err(SyntaxError::new(
v.span().clone(),
"expect either ';' or '{'",
));
for (i, a) in attrs.iter().enumerate() {
if let Attribute::Repr(_, _) = a {
repr = Some(i);
break;
}
}

if let Some(i) = repr {
let repr = match attrs.remove(i) {
Attribute::Repr(n, r) => r,
_ => unreachable!(),
};

lex.next_semicolon()?;

return Ok(Struct::Primitive(attrs, repr, def, name));
}

// Parse fields.
lex.next_oc()?;

loop {
let tok = match lex.next()? {
Some(v) => v,
None => {
return Err(SyntaxError::new(
lex.last().unwrap().clone(),
"expect an '}'",
"expect '}' after this",
));
}
};

match tok {
Token::CloseCurly(_) => break,
t => return Err(SyntaxError::new(t.span().clone(), "expect an '}'")),
t => return Err(SyntaxError::new(t.span().clone(), "expect '}'")),
}
}

Ok(Struct::new(attrs, def, name))
Ok(Struct::Composite(attrs, def, name))
}

fn parse_class(
Expand Down
25 changes: 14 additions & 11 deletions stage0/src/ast/struc.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::Attribute;
use super::{Attribute, Representation};
use crate::lexer::{Identifier, Span, StructKeyword};

/// A struct.
Expand All @@ -7,22 +7,25 @@ use crate::lexer::{Identifier, Span, StructKeyword};
/// All fields must also be a struct and will always public.
///
/// Struct type cannot be a generic type and does not supports inheritance.
pub struct Struct {
attrs: Vec<Attribute>,
def: StructKeyword,
name: Identifier,
pub enum Struct {
Primitive(Vec<Attribute>, Representation, StructKeyword, Identifier),
Composite(Vec<Attribute>, StructKeyword, Identifier),
}

impl Struct {
pub fn new(attrs: Vec<Attribute>, def: StructKeyword, name: Identifier) -> Self {
Self { attrs, def, name }
}

pub fn span(&self) -> &Span {
self.def.span()
let def = match self {
Self::Primitive(_, _, d, _) => d,
Self::Composite(_, d, _) => d,
};

def.span()
}

pub fn name(&self) -> &Identifier {
&self.name
match self {
Self::Primitive(_, _, _, i) => i,
Self::Composite(_, _, i) => i,
}
}
}
38 changes: 26 additions & 12 deletions stage0/src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub use self::func::*;
pub use self::resolver::*;
pub use self::ty::*;

use crate::ast::{Path, Use};
use crate::ast::{Path, Representation, SourceFile, Struct, TypeDefinition, Use};
use crate::pkg::PackageVersion;
use llvm_sys::core::{
LLVMContextCreate, LLVMContextDispose, LLVMDisposeModule, LLVMModuleCreateWithNameInContext,
Expand Down Expand Up @@ -54,16 +54,10 @@ impl<'a> Codegen<'a> {
// TODO: Create a mangleg name according to Itanium C++ ABI.
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html might be useful.
if self.version.major() == 0 {
format!(
"{}::0.{}::{}.{}",
self.pkg,
self.version.minor(),
container,
name
)
format!("{}::{}.{}", self.pkg, container, name)
} else {
format!(
"{}::{}::{}.{}",
"{}::v{}::{}.{}",
self.pkg,
self.version.major(),
container,
Expand Down Expand Up @@ -110,10 +104,30 @@ impl<'a> Codegen<'a> {
None => name.to_string(),
};

// Get LLVM type.
let ty = self.resolver.resolve(&name)?;
// Resolve type and build LLVM type.
let ty = match self.resolver.resolve(&name)? {
ResolvedType::Project(v) => self.build_project_type(&name, v),
ResolvedType::External(_) => todo!(),
};

Some(ty)
}

fn build_project_type(&self, name: &str, ty: &SourceFile) -> LlvmType<'_, 'a> {
match ty.ty().unwrap() {
TypeDefinition::Struct(v) => self.build_project_struct(name, v),
TypeDefinition::Class(_) => todo!(),
}
}

todo!()
fn build_project_struct(&self, name: &str, ty: &Struct) -> LlvmType<'_, 'a> {
match ty {
Struct::Primitive(_, r, _, _) => match r {
Representation::U8 => LlvmType::U8(LlvmU8::new(self)),
Representation::Un => todo!(),
},
Struct::Composite(_, _, _) => todo!(),
}
}
}

Expand Down
Loading

0 comments on commit b460e38

Please sign in to comment.