wip: more work on the compiler. I think I went the wrong direction.
This commit is contained in:
parent
2efe1a3cf1
commit
f6eccebb27
9 changed files with 442 additions and 39 deletions
|
@ -30,3 +30,9 @@ impl<T: Debug> IndexedVec<T> {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct IndexedVecKey<T: Debug>(usize, PhantomData<T>);
|
||||
|
||||
impl<T: Debug> From<IndexedVecKey<T>> for usize {
|
||||
fn from(key: IndexedVecKey<T>) -> Self {
|
||||
key.0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,19 +29,19 @@ impl<T: Debug> UniqueVec<T> {
|
|||
self.data.get(key.0)
|
||||
}
|
||||
|
||||
pub fn find_by<F>(&self, pred: F) -> Option<UniqueVecKey<T>>
|
||||
pub fn find_by<F>(&self, predicate: F) -> Option<UniqueVecKey<T>>
|
||||
where
|
||||
F: Fn(&T) -> bool,
|
||||
{
|
||||
self.data
|
||||
.iter()
|
||||
.position(pred)
|
||||
.position(predicate)
|
||||
.map(|i| UniqueVecKey(i, PhantomData))
|
||||
}
|
||||
|
||||
pub fn replace(&mut self, key: UniqueVecKey<T>, value: T) {
|
||||
let elem = self.data.get_mut(key.0).unwrap();
|
||||
*elem = value;
|
||||
let element = self.data.get_mut(key.0).unwrap();
|
||||
*element = value;
|
||||
}
|
||||
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
use crate::instructions::Instruction;
|
||||
use crate::module::{Module, StringKey, TypeKey};
|
||||
use crate::module::{BlockKey, Module, StringKey, TypeKey};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Builder<'a> {
|
||||
module: &'a mut Module,
|
||||
block: BlockKey,
|
||||
}
|
||||
|
||||
impl<'a> Builder<'a> {
|
||||
pub fn new(module: &'a mut Module) -> Builder<'a> {
|
||||
Builder { module }
|
||||
pub fn new(module: &'a mut Module, block: Option<BlockKey>) -> Builder<'a> {
|
||||
let block = block
|
||||
.unwrap_or(module.current_block.peek().unwrap().clone())
|
||||
.clone();
|
||||
Builder { module, block }
|
||||
}
|
||||
|
||||
pub fn push_atom(&mut self, value: StringKey) {
|
||||
|
@ -36,8 +40,21 @@ impl<'a> Builder<'a> {
|
|||
self.push_instruction(Instruction::PushString(value.into()));
|
||||
}
|
||||
|
||||
pub fn jump(&mut self, target: BlockKey) {
|
||||
self.push_instruction(Instruction::Jump(target.into()));
|
||||
}
|
||||
|
||||
pub fn jump_if_true(&mut self, target: BlockKey) {
|
||||
self.push_instruction(Instruction::JumpIfTrue(target.into()));
|
||||
}
|
||||
|
||||
fn push_instruction(&mut self, inst: Instruction) {
|
||||
let block = self.module.current_block_mut();
|
||||
let block_id = self.block.clone();
|
||||
let block = self
|
||||
.module
|
||||
.blocks
|
||||
.get_mut(block_id.clone())
|
||||
.expect(&format!("Unable to get block {:?}", block_id));
|
||||
block.push_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,3 +38,21 @@ impl From<(&Path, outrun_parser::Error)> for Error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<outrun_lexer::Error> for Error {
|
||||
fn from(error: outrun_lexer::Error) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Lex(error),
|
||||
file: "unknown".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<outrun_parser::Error> for Error {
|
||||
fn from(error: outrun_parser::Error) -> Error {
|
||||
Error {
|
||||
kind: ErrorKind::Parse(error),
|
||||
file: "unknown".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,4 +6,6 @@ pub enum Instruction {
|
|||
PushFloat(f64),
|
||||
PushInteger(i64),
|
||||
PushString(usize),
|
||||
Jump(usize),
|
||||
JumpIfTrue(usize),
|
||||
}
|
||||
|
|
|
@ -2,18 +2,23 @@ extern crate outrun_common;
|
|||
extern crate outrun_lexer;
|
||||
extern crate outrun_parser;
|
||||
|
||||
use outrun_lexer::TokenKind;
|
||||
use outrun_parser::{Node, NodeKind, NodeValue};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
mod block;
|
||||
mod builder;
|
||||
mod error;
|
||||
mod instructions;
|
||||
mod message;
|
||||
mod module;
|
||||
|
||||
use builder::Builder;
|
||||
pub use error::Error;
|
||||
pub use module::Module;
|
||||
pub use module::{BlockKey, Module, StringKey, TypeKey};
|
||||
|
||||
use crate::block::Block;
|
||||
|
||||
pub fn compile_file(path: &Path) -> Result<(), Error> {
|
||||
println!("*** Compiling file: {}", path.to_str().unwrap());
|
||||
|
@ -24,39 +29,317 @@ pub fn compile_file(path: &Path) -> Result<(), Error> {
|
|||
|
||||
let mut module = Module::new(Some(path.to_str().unwrap()));
|
||||
for node in nodes {
|
||||
visit(node, &mut module);
|
||||
visit(&node, &mut module);
|
||||
}
|
||||
println!("MODULE: {:?}", module);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit(node: Node, module: &mut Module) {
|
||||
pub fn compile_string(input: &str) -> Result<(), Error> {
|
||||
let nodes = outrun_lexer::lex_string(input)
|
||||
.map_err(Error::from)
|
||||
.and_then(|tokens| outrun_parser::parse(&tokens).map_err(|e| Error::from(e)))?;
|
||||
|
||||
let mut module = Module::new::<String>(None);
|
||||
for node in nodes {
|
||||
visit(&node, &mut module);
|
||||
}
|
||||
println!("MODULE: {:#?}", module);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn visit(node: &Node, mut module: &mut Module) {
|
||||
match node.kind {
|
||||
NodeKind::Atom => {
|
||||
let atom = module.strings.insert(node.value.as_string().unwrap());
|
||||
Builder::new(module).push_atom(atom);
|
||||
Builder::new(module, None).push_atom(atom);
|
||||
}
|
||||
NodeKind::Block => {
|
||||
for node in node.value.as_nodes().unwrap() {
|
||||
visit(&node, &mut module);
|
||||
}
|
||||
}
|
||||
NodeKind::Boolean => {
|
||||
let value = node.value.as_bool().unwrap();
|
||||
Builder::new(module).push_boolean(value);
|
||||
Builder::new(module, None).push_boolean(value);
|
||||
}
|
||||
NodeKind::Constant => {
|
||||
let value = module.reference_type(node.value.as_string().unwrap());
|
||||
Builder::new(module).push_constant(value);
|
||||
Builder::new(module, None).push_constant(value);
|
||||
}
|
||||
NodeKind::Definition => {
|
||||
match node.value.clone() {
|
||||
// NodeValue::Definition { kind: TokenKind::KeywordStruct, .. } => visit_struct(node, module),
|
||||
NodeValue::Definition {
|
||||
kind: TokenKind::KeywordProtocol,
|
||||
name,
|
||||
fields,
|
||||
arguments,
|
||||
result,
|
||||
} => visit_protocol(name, fields, arguments, result, module),
|
||||
// NodeValue::Definition { kind: TokenKind::KeywordImpl,.. } => visit_impl(node, module),
|
||||
NodeValue::Definition {
|
||||
kind: TokenKind::KeywordDef,
|
||||
name,
|
||||
fields,
|
||||
arguments,
|
||||
result,
|
||||
} => visit_def(name, fields, arguments, result, module),
|
||||
NodeValue::Definition {
|
||||
kind: TokenKind::KeywordDefPrivate,
|
||||
name,
|
||||
fields,
|
||||
arguments,
|
||||
result,
|
||||
} => visit_defp(name, fields, arguments, result, module),
|
||||
NodeValue::Definition {
|
||||
kind: TokenKind::KeywordDefStatic,
|
||||
name,
|
||||
fields,
|
||||
arguments,
|
||||
result,
|
||||
} => visit_defs(name, fields, arguments, result, module),
|
||||
_ => panic!("NOT A PROTOCOL"),
|
||||
}
|
||||
}
|
||||
NodeKind::Documentation => {
|
||||
let value = node.value.as_string().unwrap();
|
||||
let key = module.strings.insert(value);
|
||||
module.current_doc = Some(key);
|
||||
}
|
||||
NodeKind::Float => {
|
||||
let value = node.value.as_float().unwrap();
|
||||
Builder::new(module).push_float(value);
|
||||
Builder::new(module, None).push_float(value);
|
||||
}
|
||||
NodeKind::Integer => {
|
||||
let value = node.value.as_integer().unwrap();
|
||||
Builder::new(module).push_integer(value);
|
||||
Builder::new(module, None).push_integer(value);
|
||||
}
|
||||
NodeKind::String => {
|
||||
let value = node.value.as_string().unwrap();
|
||||
Builder::new(module).push_string(value);
|
||||
Builder::new(module, None).push_string(value);
|
||||
}
|
||||
NodeKind::Module => {
|
||||
for node in node.value.as_nodes().unwrap() {
|
||||
visit(node, &mut module);
|
||||
}
|
||||
}
|
||||
_ => panic!("Can't handle: {:#?}", node),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_protocol(
|
||||
name: Box<Node>,
|
||||
fields: Vec<Node>,
|
||||
arguments: Vec<Node>,
|
||||
result: Option<Box<Node>>,
|
||||
mut module: &mut Module,
|
||||
) {
|
||||
let name = eval_constant_name(&name);
|
||||
if !fields.is_empty() {
|
||||
let span = fields
|
||||
.first()
|
||||
.unwrap()
|
||||
.span
|
||||
.extend(fields.last().unwrap().span);
|
||||
module.warning("Protocol definitions do not have fields", span);
|
||||
}
|
||||
|
||||
if let Some(result) = result {
|
||||
module.warning("Protocol definitions do no have return types", result.span);
|
||||
}
|
||||
|
||||
let mut arguments = deconstruct_keyword_list(&arguments);
|
||||
|
||||
let requires = arguments
|
||||
.remove("requires")
|
||||
.map(|node| eval_type_expr_to_keys(node, &mut module))
|
||||
.unwrap_or_else(|| vec![]);
|
||||
|
||||
let protocol_type = module.new_protocol_type(Some(name), requires, module.current_doc.clone());
|
||||
module.current_doc = None;
|
||||
module
|
||||
.current_definition
|
||||
.push(protocol_type.clone())
|
||||
.unwrap();
|
||||
|
||||
let body = arguments.remove("as");
|
||||
|
||||
for (key, node) in arguments.iter() {
|
||||
module.warning(&format!("Unknown protocol argument {}", key), node.span);
|
||||
}
|
||||
|
||||
if let Some(body) = body {
|
||||
visit(body, &mut module);
|
||||
}
|
||||
|
||||
module.current_definition.pop().unwrap();
|
||||
println!("defining protocol: {:?}", protocol_type);
|
||||
println!(" => body: {:#?}", body);
|
||||
}
|
||||
|
||||
fn visit_def(
|
||||
name: Box<Node>,
|
||||
fields: Vec<Node>,
|
||||
arguments: Vec<Node>,
|
||||
result: Option<Box<Node>>,
|
||||
module: &mut Module,
|
||||
) {
|
||||
let name = name.value.as_string().unwrap();
|
||||
println!("def {:#?}", name);
|
||||
|
||||
let fields = deconstruct_keyword_list(&fields)
|
||||
.iter()
|
||||
.map(|(key, value)| {
|
||||
let arg_type_keys = eval_type_expr_to_keys(value, module);
|
||||
let arg_type = module.new_protocol_type::<String>(None, arg_type_keys, None);
|
||||
let string_key = module.strings.insert(key.to_string());
|
||||
(string_key, arg_type)
|
||||
})
|
||||
.collect::<Vec<(StringKey, TypeKey)>>();
|
||||
|
||||
let return_type = result
|
||||
.map(|node| {
|
||||
let result_keys = eval_type_expr_to_keys(&node, module);
|
||||
module.new_protocol_type::<String>(None, result_keys, None)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
module.push_function(name, &fields, return_type);
|
||||
|
||||
let mut arguments = deconstruct_keyword_list(&arguments);
|
||||
|
||||
let entry_block = module.current_block.peek().cloned().unwrap();
|
||||
let body_block = module.push_block();
|
||||
|
||||
if let Some(guard) = arguments.remove("guard") {
|
||||
visit(guard, module);
|
||||
let mut builder = Builder::new(module, Some(entry_block));
|
||||
builder.jump_if_true(body_block);
|
||||
} else {
|
||||
let mut builder = Builder::new(module, Some(entry_block));
|
||||
builder.jump(body_block);
|
||||
}
|
||||
|
||||
if let Some(body) = arguments.remove("as") {
|
||||
visit(body, module);
|
||||
}
|
||||
|
||||
module.pop_block();
|
||||
module.pop_function();
|
||||
}
|
||||
|
||||
fn visit_defp(
|
||||
name: Box<Node>,
|
||||
fields: Vec<Node>,
|
||||
arguments: Vec<Node>,
|
||||
result: Option<Box<Node>>,
|
||||
module: &mut Module,
|
||||
) {
|
||||
let name = name.value.as_string().unwrap();
|
||||
println!("defp {:#?}", name);
|
||||
}
|
||||
|
||||
fn visit_defs(
|
||||
name: Box<Node>,
|
||||
fields: Vec<Node>,
|
||||
arguments: Vec<Node>,
|
||||
result: Option<Box<Node>>,
|
||||
module: &mut Module,
|
||||
) {
|
||||
let name = name.value.as_string().unwrap();
|
||||
println!("defs {:#?}", name);
|
||||
}
|
||||
|
||||
fn eval_constant_name(node: &Node) -> String {
|
||||
match node.kind {
|
||||
NodeKind::Constant => node.value.as_string().unwrap(),
|
||||
NodeKind::Infix => match node.value {
|
||||
NodeValue::Infix(ref lhs, TokenKind::Dot, ref rhs) => {
|
||||
let lhs = eval_constant_name(lhs);
|
||||
let rhs = eval_constant_name(rhs);
|
||||
format!("{}.{}", lhs, rhs)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_type_expr(node: &Node, mut output: Vec<String>) -> Vec<String> {
|
||||
match node.kind {
|
||||
NodeKind::Constant => {
|
||||
output.push(node.value.as_string().unwrap());
|
||||
return output;
|
||||
}
|
||||
NodeKind::Infix => match node.value {
|
||||
NodeValue::Infix(ref lhs, TokenKind::Plus, ref rhs) => {
|
||||
let output = eval_type_expr(lhs, output);
|
||||
let output = eval_type_expr(rhs, output);
|
||||
return output;
|
||||
}
|
||||
NodeValue::Infix(ref lhs, TokenKind::Dot, ref rhs) => {
|
||||
let lhs = eval_constant_name(lhs);
|
||||
let rhs = eval_constant_name(rhs);
|
||||
output.push(format!("{}.{}", lhs, rhs));
|
||||
return output;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_type_expr_to_keys(node: &Node, module: &mut Module) -> Vec<TypeKey> {
|
||||
eval_type_expr(node, vec![])
|
||||
.iter()
|
||||
.map(|type_name| module.reference_type(type_name))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn deconstruct_keyword_list(keyword_list: &[Node]) -> HashMap<&str, &Box<Node>> {
|
||||
keyword_list
|
||||
.iter()
|
||||
.filter_map(|node| match node.value {
|
||||
NodeValue::KeywordPair(ref key, ref value) => {
|
||||
let key = key.value.as_str().unwrap();
|
||||
Some((key, value))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.collect::<HashMap<&str, &Box<Node>>>()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_protocol() {
|
||||
let source = r#"
|
||||
```doc
|
||||
# Boolean
|
||||
|
||||
Provides a common interface for values masquerading as Booleans.
|
||||
```
|
||||
protocol Boolean, requires: Fruit.Bats + Vampire.Bats, as: do
|
||||
```doc
|
||||
A mechanism for values to convert themselves into a concrete boolean value.
|
||||
|
||||
Must be implemented.
|
||||
```
|
||||
def true?(self: Self): Outrun.Core.Boolean
|
||||
|
||||
```doc
|
||||
Is the value false?
|
||||
```
|
||||
def false?(self: Self): Outrun.Core.Boolean, as: !true?(self)
|
||||
end
|
||||
"#;
|
||||
compile_string(&source);
|
||||
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
|
|
40
outrun-compiler/src/message.rs
Normal file
40
outrun-compiler/src/message.rs
Normal file
|
@ -0,0 +1,40 @@
|
|||
use outrun_lexer::Span;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MessageSeverity {
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Message {
|
||||
message: String,
|
||||
severity: MessageSeverity,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn info<T: ToString>(message: T, span: Span) -> Message {
|
||||
Message {
|
||||
message: message.to_string(),
|
||||
severity: MessageSeverity::Info,
|
||||
span,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn warning<T: ToString>(message: T, span: Span) -> Message {
|
||||
Message {
|
||||
message: message.to_string(),
|
||||
severity: MessageSeverity::Warning,
|
||||
span,
|
||||
}
|
||||
}
|
||||
pub fn error<T: ToString>(message: T, span: Span) -> Message {
|
||||
Message {
|
||||
message: message.to_string(),
|
||||
severity: MessageSeverity::Error,
|
||||
span,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +1,27 @@
|
|||
use crate::block::Block;
|
||||
use crate::message::Message;
|
||||
use outrun_common::indexed_vec::{IndexedVec, IndexedVecKey};
|
||||
use outrun_common::stack::Stack;
|
||||
use outrun_common::unique_vec::{UniqueVec, UniqueVecKey};
|
||||
use outrun_lexer::Span;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub type TypeKey = UniqueVecKey<Type>;
|
||||
pub type BlockKey = IndexedVecKey<Block>;
|
||||
pub type StringKey = UniqueVecKey<String>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Module {
|
||||
pub strings: UniqueVec<String>,
|
||||
location: Option<StringKey>,
|
||||
blocks: IndexedVec<Block>,
|
||||
pub(crate) blocks: IndexedVec<Block>,
|
||||
functions: HashMap<StringKey, Function>,
|
||||
current_block: Stack<IndexedVecKey<Block>>,
|
||||
pub(crate) current_block: Stack<IndexedVecKey<Block>>,
|
||||
current_function: Stack<StringKey>,
|
||||
types: UniqueVec<Type>,
|
||||
messages: Vec<Message>,
|
||||
pub current_doc: Option<StringKey>,
|
||||
pub current_definition: Stack<TypeKey>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
|
@ -28,6 +34,9 @@ impl Module {
|
|||
let current_block = Stack::new();
|
||||
let current_function = Stack::new();
|
||||
let types = UniqueVec::new(|l: &Type, r: &Type| l.name() == r.name());
|
||||
let messages = Vec::new();
|
||||
let current_doc = None;
|
||||
let current_definition = Stack::new();
|
||||
|
||||
Module {
|
||||
strings,
|
||||
|
@ -37,9 +46,24 @@ impl Module {
|
|||
current_block,
|
||||
current_function,
|
||||
types,
|
||||
messages,
|
||||
current_doc,
|
||||
current_definition,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info<T: ToString>(&mut self, message: T, span: Span) {
|
||||
self.messages.push(Message::info(message, span));
|
||||
}
|
||||
|
||||
pub fn warning<T: ToString>(&mut self, message: T, span: Span) {
|
||||
self.messages.push(Message::warning(message, span));
|
||||
}
|
||||
|
||||
pub fn error<T: ToString>(&mut self, message: T, span: Span) {
|
||||
self.messages.push(Message::error(message, span));
|
||||
}
|
||||
|
||||
pub fn push_function<T: ToString>(
|
||||
&mut self,
|
||||
name: T,
|
||||
|
@ -68,13 +92,17 @@ impl Module {
|
|||
self.current_function.pop().ok()
|
||||
}
|
||||
|
||||
pub fn push_block(&mut self) -> IndexedVecKey<Block> {
|
||||
pub fn push_block(&mut self) -> BlockKey {
|
||||
let block = Block::new();
|
||||
let block_id = self.blocks.insert(block);
|
||||
self.current_block.push(block_id.clone()).unwrap();
|
||||
block_id
|
||||
}
|
||||
|
||||
pub fn pop_block(&mut self) -> Option<BlockKey> {
|
||||
self.current_block.pop().ok()
|
||||
}
|
||||
|
||||
pub fn current_block_mut(&mut self) -> &mut Block {
|
||||
let block_id = self.current_block.peek().unwrap();
|
||||
self.blocks.get_mut(block_id.clone()).unwrap()
|
||||
|
@ -99,17 +127,17 @@ impl Module {
|
|||
&mut self,
|
||||
name: Option<T>,
|
||||
requirements: Vec<TypeKey>,
|
||||
docs: Option<StringKey>,
|
||||
) -> TypeKey {
|
||||
let name = name
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| {
|
||||
Some(
|
||||
requirements
|
||||
.iter()
|
||||
.map(|k| self.name_of(k.clone()))
|
||||
.collect::<Vec<&str>>()
|
||||
.join("+"),
|
||||
)
|
||||
let mut requirements = requirements
|
||||
.iter()
|
||||
.map(|k| self.name_of(k.clone()))
|
||||
.collect::<Vec<&str>>();
|
||||
requirements.sort();
|
||||
Some(requirements.join("+"))
|
||||
})
|
||||
.map(|s| self.strings.insert(s))
|
||||
.unwrap();
|
||||
|
@ -117,6 +145,7 @@ impl Module {
|
|||
let new_type = Type::Protocol {
|
||||
name: name.clone(),
|
||||
requirements,
|
||||
docs,
|
||||
};
|
||||
|
||||
if let Some(key) = self.types.find_by(|t| t.name() == name) {
|
||||
|
@ -125,13 +154,18 @@ impl Module {
|
|||
self.types.replace(key.clone(), new_type);
|
||||
return key;
|
||||
}
|
||||
panic!("Attempt to overwrite existing type {:#?}", r#type);
|
||||
panic!("Attempt to overwrite existing type {:#?}", (r#type, name));
|
||||
}
|
||||
|
||||
self.types.insert(new_type)
|
||||
}
|
||||
|
||||
pub fn new_struct_type<T: ToString>(&mut self, name: T, fields: Vec<(T, TypeKey)>) -> TypeKey {
|
||||
pub fn new_struct_type<T: ToString>(
|
||||
&mut self,
|
||||
name: T,
|
||||
fields: Vec<(T, TypeKey)>,
|
||||
docs: Option<StringKey>,
|
||||
) -> TypeKey {
|
||||
let name = self.strings.insert(name.to_string());
|
||||
let (field_names, field_types) = fields.iter().fold(
|
||||
(Vec::new(), Vec::new()),
|
||||
|
@ -146,6 +180,7 @@ impl Module {
|
|||
name: name.clone(),
|
||||
field_names,
|
||||
field_types,
|
||||
docs,
|
||||
};
|
||||
|
||||
if let Some(key) = self.types.find_by(|t| t.name() == name) {
|
||||
|
@ -191,10 +226,12 @@ pub enum Type {
|
|||
name: StringKey,
|
||||
field_names: Vec<StringKey>,
|
||||
field_types: Vec<TypeKey>,
|
||||
docs: Option<StringKey>,
|
||||
},
|
||||
Protocol {
|
||||
name: StringKey,
|
||||
requirements: Vec<TypeKey>,
|
||||
docs: Option<StringKey>,
|
||||
},
|
||||
Integer(StringKey),
|
||||
Boolean(StringKey),
|
||||
|
|
|
@ -36,14 +36,14 @@ fn collect_files(path: &Path, mut files: Vec<PathBuf>) -> Result<Vec<PathBuf>, E
|
|||
Ok(files)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
// #[cfg(test)]
|
||||
// mod test {
|
||||
// use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_init() {
|
||||
let result = init().unwrap();
|
||||
println!("result: {:?}", result);
|
||||
assert!(false);
|
||||
}
|
||||
}
|
||||
// #[test]
|
||||
// fn test_init() {
|
||||
// let result = init().unwrap();
|
||||
// println!("result: {:?}", result);
|
||||
// assert!(false);
|
||||
// }
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue