Skip to content

Commit

Permalink
Struct access + Basic Enums
Browse files Browse the repository at this point in the history
  • Loading branch information
ecton committed Apr 24, 2024
1 parent 370580c commit 1c54414
Show file tree
Hide file tree
Showing 8 changed files with 541 additions and 129 deletions.
59 changes: 54 additions & 5 deletions src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use syntax::{
};

use crate::runtime::symbol::Symbol;
use crate::runtime::types::BitcodeType;
use crate::runtime::types::{self, BitcodeEnum, BitcodeStruct};

use crate::vm::bitcode::{
Access, Accessable, BinaryKind, BitcodeBlock, BitcodeFunction, FaultKind, Label, Op,
OpDestination, ValueOrSource,
Expand Down Expand Up @@ -295,6 +296,7 @@ impl Compiler {
}
}
}
Expression::Enum(_e) => {}
Expression::SingleMatch(e) => {
self.expand_macros(&mut e.value);
if let Some(guard) = &mut e.pattern.guard {
Expand Down Expand Up @@ -809,24 +811,31 @@ impl<'a> Scope<'a> {
},
);
} else {
todo!("struct functions can't be anonymous")
self.compiler.errors.push(Ranged::new(
expr.range(),
Error::StructFunctionRequiresName,
))
}
}
}
}
}

let ty = BitcodeType {
let ty = BitcodeStruct {
name: e.name.0.clone(),
functions,
fields,
};

// TODO struct access
let access = if e.visibility.is_some() {
Access::Public
} else {
Access::Private
};
if self.is_module_root() {
self.compiler
.code
.declare(e.name.0.clone(), false, Access::Public, ty, dest);
.declare(e.name.0.clone(), false, access, ty, dest);
} else {
let stack = self.new_temporary();
self.compiler.code.copy(ty, stack);
Expand Down Expand Up @@ -864,6 +873,38 @@ impl<'a> Scope<'a> {
self.compiler.code.call(kind, arity * 2);
self.compiler.code.copy(Register(0), dest);
}
Expression::Enum(e) => {
let mut variants = Vec::new();
let mut value = 0;

for variant in &e.variants.enclosed {
variants.push(types::EnumVariant {
name: variant.name.0.clone(),
value: ValueOrSource::UInt(value),
});
value += 1;
}

let ty = BitcodeEnum {
name: e.name.0.clone(),
variants,
};

let access = if e.visibility.is_some() {
Access::Public
} else {
Access::Private
};
if self.is_module_root() {
self.compiler
.code
.declare(e.name.0.clone(), false, access, ty, dest);
} else {
let stack = self.new_temporary();
self.compiler.code.copy(ty, stack);
self.declare_local(e.name.0.clone(), false, stack, dest);
}
}
Expression::Module(module) => {
let block = &module.contents.0;
let mut mod_compiler = Compiler::default();
Expand Down Expand Up @@ -2015,6 +2056,7 @@ impl<'a> Scope<'a> {
| Expression::RootModule
| Expression::Structure(_)
| Expression::StructureLiteral(_)
| Expression::Enum(_)
| Expression::FormatString(_) => Err(expr.1),
Expression::Macro(_) | Expression::InfixMacro(_) => {
unreachable!("macros should be expanded already")
Expand Down Expand Up @@ -2269,6 +2311,7 @@ impl<'a> Scope<'a> {
| Expression::RootModule
| Expression::Return(_)
| Expression::StructureLiteral(_)
| Expression::Enum(_)
| Expression::FormatString(_) => {
ValueOrSource::Stack(self.compile_expression_into_temporary(source))
}
Expand Down Expand Up @@ -2463,6 +2506,8 @@ pub enum Error {
UsizeTooLarge,
/// A public function requires a name.
PublicFunctionRequiresName,
/// A function in a structure requires a name.
StructFunctionRequiresName,
/// A label is not valid.
InvalidLabel,
/// Public declarations can only exist within a module's scope.
Expand Down Expand Up @@ -2492,6 +2537,7 @@ impl crate::ErrorKind for Error {
Error::TooManyArguments => "too many arguments",
Error::UsizeTooLarge => "usize too large",
Error::PublicFunctionRequiresName => "public function must have a name",
Error::StructFunctionRequiresName => "functions in structs must have a name",
Error::InvalidLabel => "invalid label",
Error::PubOnlyInModules => "pub only in modules",
Error::ExpectedBlock => "expected block",
Expand All @@ -2516,6 +2562,9 @@ impl Display for Error {
f.write_str("integer too large for the architecture's index type")
}
Error::PublicFunctionRequiresName => f.write_str("public function must have a name"),
Error::StructFunctionRequiresName => {
f.write_str("functions in structs must have a name")
}
Error::InvalidLabel => f.write_str("invalid label"),
Error::PubOnlyInModules => {
f.write_str("declarations may only be published within modules")
Expand Down
141 changes: 139 additions & 2 deletions src/compiler/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,17 @@ where
}
}

impl<T> TokenizeInto for Option<T>
where
T: TokenizeInto,
{
fn tokenize_into(&self, tokens: &mut VecDeque<Ranged<Token>>) {
if let Some(inner) = self {
inner.tokenize_into(tokens);
}
}
}

/// Converts a value into a series of [`Token`]s with the provided enclosing
/// range.
pub trait TokenizeRanged {
Expand Down Expand Up @@ -641,6 +652,8 @@ pub enum Expression {
Structure(Box<StructureDefinition>),
/// A structure literal.
StructureLiteral(Box<NewStruct>),
/// An enum definition.
Enum(Box<EnumDefinition>),
/// A variable declaration.
SingleMatch(Box<SingleMatch>),
/// A macro invocation.
Expand Down Expand Up @@ -735,6 +748,7 @@ impl TokenizeRanged for Expression {
Expression::Module(it) => it.tokenize_into(tokens),
Expression::Structure(it) => it.tokenize_into(tokens),
Expression::StructureLiteral(it) => it.tokenize_into(tokens),
Expression::Enum(it) => it.tokenize_into(tokens),
Expression::Function(it) => it.tokenize_into(tokens),
Expression::SingleMatch(it) => it.tokenize_into(tokens),
Expression::Macro(it) => it.tokenize_into(tokens),
Expand Down Expand Up @@ -1316,6 +1330,41 @@ impl TokenizeInto for StructureMember {
}
}

/// A custom enum type definition.
#[derive(Debug, Clone, PartialEq)]
pub struct EnumDefinition {
/// The visibility keyword, if specified.
pub visibility: Option<Ranged<Symbol>>,
/// The enum keyword.
pub r#enum: Ranged<Token>,
/// The name of the enum.
pub name: Ranged<Symbol>,
/// The variants of the enum, if present.
pub variants: Enclosed<Delimited<Ranged<EnumVariant>>>,
}

impl TokenizeInto for EnumDefinition {
fn tokenize_into(&self, tokens: &mut VecDeque<Ranged<Token>>) {
self.visibility.tokenize_into(tokens);
tokens.push_back(self.r#enum.clone());
self.name.tokenize_into(tokens);
self.variants.tokenize_into(tokens);
}
}

/// A custom enum type definition.
#[derive(Debug, Clone, PartialEq)]
pub struct EnumVariant {
/// The name of the variant.
pub name: Ranged<Symbol>,
}

impl TokenizeInto for EnumVariant {
fn tokenize_into(&self, tokens: &mut VecDeque<Ranged<Token>>) {
self.name.tokenize_into(tokens);
}
}

/// The syntax components of a function call.
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionCall {
Expand Down Expand Up @@ -1775,6 +1824,10 @@ pub enum ParseError {
ExpectedModuleBody,
/// Expected a function body.
ExpectedFunctionBody,
/// Expected an enum body.
ExpectedEnumBody,
/// Expected an enum variant.
ExpectedEnumVariant,
/// Expected the `in` keyword.
ExpectedIn,
/// Expected function parameters.
Expand Down Expand Up @@ -1819,6 +1872,8 @@ impl crate::ErrorKind for ParseError {
ParseError::ExpectedBlock => "expected block",
ParseError::ExpectedModuleBody => "expected module body",
ParseError::ExpectedFunctionBody => "expected function body",
ParseError::ExpectedEnumBody => "expected enum body",
ParseError::ExpectedEnumVariant => "expected enum variant",
ParseError::ExpectedStructureMember => "expected structure member",
ParseError::ExpectedIn => "expected in",
ParseError::ExpectedFunctionParameters => "expected function parameters",
Expand Down Expand Up @@ -1858,6 +1913,8 @@ impl Display for ParseError {
ParseError::ExpectedBlock => f.write_str("expected a block"),
ParseError::ExpectedModuleBody => f.write_str("expected a module body"),
ParseError::ExpectedFunctionBody => f.write_str("expected function body"),
ParseError::ExpectedEnumBody => f.write_str("expected enum body"),
ParseError::ExpectedEnumVariant => f.write_str("expected enum variant"),
ParseError::ExpectedStructureMember => f.write_str("expected structure member"),
ParseError::ExpectedIn => f.write_str("expected \"in\""),
ParseError::ExpectedFunctionParameters => f.write_str("expected function parameters"),
Expand Down Expand Up @@ -3776,8 +3833,8 @@ impl Struct {
return Err(name_token.map(|_| ParseError::ExpectedName));
};

let brace = tokens.next(ParseError::ExpectedModuleBody)?;
let members = if brace.0 == Token::Open(Paired::Brace) {
let members = if tokens.peek_token() == Some(Token::Open(Paired::Brace)) {
let brace = tokens.next_or_eof()?;
let mut members = Delimited::build_empty();
let (_, close) = parse_paired(Paired::Brace, ';', tokens, |delimiter, tokens| {
if let Some(delimiter) = delimiter {
Expand Down Expand Up @@ -3843,6 +3900,85 @@ impl Struct {
}
}

struct Enum;

impl Parselet for Enum {
fn token(&self) -> Option<Token> {
None
}

fn matches(&self, token: &Token, tokens: &mut TokenReader<'_>) -> bool {
matches!(token, Token::Identifier(ident) if ident == Symbol::enum_symbol())
&& tokens
.peek_token()
.map_or(false, |t| matches!(t, Token::Identifier(_)))
}
}

impl PrefixParselet for Enum {
fn parse_prefix(
&self,
token: Ranged<Token>,
tokens: &mut TokenReader<'_>,
config: &ParserConfig<'_>,
) -> Result<Ranged<Expression>, Ranged<ParseError>> {
Self::parse_enum(None, token, tokens, config)
}
}

impl Enum {
fn parse_enum(
visibility: Option<Ranged<Symbol>>,
r#enum: Ranged<Token>,
tokens: &mut TokenReader<'_>,
config: &ParserConfig<'_>,
) -> Result<Ranged<Expression>, Ranged<ParseError>> {
let name_token = tokens.next(ParseError::ExpectedName)?;
let Token::Identifier(name) = name_token.0 else {
return Err(name_token.map(|_| ParseError::ExpectedName));
};

let brace = tokens.next(ParseError::ExpectedEnumBody)?;
if brace.0 != Token::Open(Paired::Brace) {
return Err(brace.map(|_| ParseError::ExpectedEnumBody));
}
let mut members = Delimited::build_empty();
let (_, close) = parse_paired(Paired::Brace, ';', tokens, |delimiter, tokens| {
if let Some(delimiter) = delimiter {
members.set_delimiter(delimiter);
}
let start = tokens.last_index;
let member = Self::parse_variant(tokens, config)?;
members.push(tokens.ranged(start.., member));
Ok(())
})?;
let variants = Enclosed {
open: brace,
close,
enclosed: members.finish(),
};

Ok(tokens.ranged(
r#enum.range().start..,
Expression::Enum(Box::new(EnumDefinition {
visibility,
r#enum,
variants,
name: Ranged::new(name_token.1, name),
})),
))
}

fn parse_variant(
tokens: &mut TokenReader<'_>,
_config: &ParserConfig<'_>,
) -> Result<EnumVariant, Ranged<ParseError>> {
let name = tokens.next_identifier(ParseError::ExpectedEnumVariant)?;

Ok(EnumVariant { name })
}
}

/// A set of match patterns.
#[derive(Default, Debug, Clone, PartialEq)]
pub struct Matches {
Expand Down Expand Up @@ -4645,6 +4781,7 @@ fn parselets() -> Parselets {
Pub,
Fn,
Struct,
Enum,
Var,
If,
True,
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/regex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ impl MuseRegex {
})
}

/// Compilex the regex literal and returns it loaded for the runtime.
pub fn load(literal: &RegexLiteral, guard: &CollectionGuard<'_>) -> Result<Value, Fault> {
MuseRegex::new(literal)
.map(|r| Value::dynamic(r, guard))
.map_err(|err| {
Fault::Exception(Value::dynamic(MuseString::from(err.to_string()), guard))
})
}

/// Returns the literal used to compile this regular expression.
#[must_use]
pub const fn literal(&self) -> &RegexLiteral {
Expand Down
Loading

0 comments on commit 1c54414

Please sign in to comment.