Skip to content

Commit

Permalink
Added basic Type Checking!
Browse files Browse the repository at this point in the history
  • Loading branch information
VonTum committed Nov 9, 2023
1 parent b11984e commit 758b3d6
Show file tree
Hide file tree
Showing 9 changed files with 302 additions and 186 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ The main goals of the language are roughly listed below:
- [x] Can Parse Multiply-Add pipeline
- [x] Can Parse Blur2 filter
- [x] If Statements
- [ ] Structs
- [ ] For Loops
- [ ] Multi-Interface Syntax
- [ ] Native Module integration syntax
Expand All @@ -60,6 +61,12 @@ The main goals of the language are roughly listed below:
- [ ] Incremental Compilation
- [ ] Multi-Threaded Compilation

### Type and Bound Checking
- [x] Basic Type Checking (bools, ints, arrays, etc)
- [ ] Types for Interfaces
- [ ] Integer and Array Bounds Checking
- [ ] Latency Checking

### LSP
- [x] Basic LSP for VSCode integration
- [x] Syntax Highlighting
Expand Down
77 changes: 25 additions & 52 deletions src/ast.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

use num::bigint::BigUint;

use crate::{tokenizer::TokenTypeIdx, linker::{NamedUUID, FileUUID}, flattening::{FlattenedModule, WireIDMarker, WireID, OutsideWireID}, arena_alloc::ListAllocator};
use crate::{tokenizer::{TokenTypeIdx, get_token_type_name}, linker::{NamedUUID, FileUUID}, flattening::{FlattenedModule, WireIDMarker, WireID, OutsideWireID}, arena_alloc::ListAllocator, typing::Type};
use core::ops::Range;
use std::ops::Deref;
use std::{ops::Deref, fmt::Display};

// Token span. Indices are INCLUSIVE
#[derive(Clone,Copy,Debug,PartialEq,Eq)]
Expand Down Expand Up @@ -54,37 +54,8 @@ pub enum TypeExpression {
Array(Box<(TypeExpression, SpanExpression)>)
}

impl TypeExpression {
pub fn get_root(&self) -> usize {
match self {
Self::Named(s) => *s,
Self::Array(b) => {
b.deref().0.get_root()
}
}
}
pub fn map_to_type<F : Fn(usize) -> NamedUUID>(&self, f : F) -> Type {
match self {
TypeExpression::Named(n) => Type::Named(f(*n)),
TypeExpression::Array(b) => {
let (sub, idx) = b.deref();
Type::Array(Box::new(sub.map_to_type(f)))
// TODO gather bound constraints
},
}
}
}

pub type SpanTypeExpression = (TypeExpression, Span);

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Type {
Named(NamedUUID),
Array(Box<Type>)
}

pub type SpanType = (Type, Span);

#[derive(Debug,Clone)]
pub struct SignalDeclaration {
pub span : Span,
Expand All @@ -98,6 +69,12 @@ pub struct Operator {
pub op_typ : TokenTypeIdx
}

impl Display for Operator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(get_token_type_name(self.op_typ))
}
}

#[derive(Debug,Clone)]
pub enum Value {
Bool(bool),
Expand Down Expand Up @@ -177,31 +154,27 @@ pub struct Module {
}

impl Module {
pub fn get_function_sugar_inputs_outputs(&self) -> (Vec<OutsideWireID>, Vec<OutsideWireID>) {
let mut decl_iter = self.declarations.iter();
pub fn get_function_sugar_inputs_outputs(&self) -> (Vec<(OutsideWireID, Type)>, Vec<(OutsideWireID, Type)>) {
let mut inputs = Vec::new();
let mut outputs = Vec::new();
let mut last = if let Some((_pos, decl)) = decl_iter.next() {
let mut last_was_output = true;
for (id, decl) in &self.declarations {
let typ = decl.typ.0.map_to_type(&self.link_info.global_references);
match decl.identifier_type {
IdentifierType::Input => IdentifierType::Input,
IdentifierType::Output => IdentifierType::Output,
IdentifierType::Local | IdentifierType::State => {return (inputs, outputs)}
}
} else {
return (inputs, outputs);
};
for (id, decl) in decl_iter {
if decl.identifier_type != last {
match decl.identifier_type {
IdentifierType::Input => {
inputs.push(OutsideWireID(id));
}
IdentifierType::Output => {
outputs.push(OutsideWireID(id));
}
IdentifierType::Local | IdentifierType::State => {
break;
IdentifierType::Input => {
if last_was_output {
inputs.clear();
}
inputs.push((OutsideWireID(id), typ));
outputs.clear();
last_was_output = false;
}
IdentifierType::Output => {
outputs.push((OutsideWireID(id), typ));
last_was_output = true;
}
IdentifierType::Local | IdentifierType::State => {
break;
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/dev_aid/lsp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,13 @@ fn convert_diagnostic(err : ParsingError, severity : DiagnosticSeverity, token_p
// Requires that token_positions.len() == tokens.len() + 1 to include EOF token
fn send_errors_warnings(connection: &Connection, errors : ErrorCollector, token_positions : &[std::ops::Range<Position>], uris : &ArenaVector<Url, FileUUIDMarker>) -> Result<(), Box<dyn Error + Sync + Send>> {
let mut diag_vec : Vec<Diagnostic> = Vec::new();
for err in errors.errors {
let (err_vec, file) = errors.get();
for err in err_vec {
diag_vec.push(convert_diagnostic(err, DiagnosticSeverity::ERROR, token_positions, uris));
}

let params = &PublishDiagnosticsParams{
uri: uris[errors.file].clone(),
uri: uris[file].clone(),
diagnostics: diag_vec,
version: None
};
Expand Down
4 changes: 2 additions & 2 deletions src/dev_aid/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,8 @@ pub fn syntax_highlight_file(file_paths : Vec<PathBuf>) {

linker.flatten_all_modules_in_file(file_uuid, &mut errors);

for err in errors.errors {
//err.pretty_print_error(f.parsing_errors.file, &token_offsets, &paths_arena, &mut file_cache);
for err in errors.get().0 {
err.pretty_print_error(f.parsing_errors.file, &token_offsets, &paths_arena, &mut file_cache);
}
}
}
19 changes: 12 additions & 7 deletions src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@


use std::{ops::Range, path::{Path, PathBuf}};
use std::{ops::Range, path::{Path, PathBuf}, cell::RefCell};

use crate::{ast::Span, linker::{FileUUID, FileUUIDMarker}, arena_alloc::ArenaVector};
use ariadne::*;
Expand Down Expand Up @@ -94,22 +94,27 @@ pub fn join_expected_list(expected : &[TokenTypeIdx]) -> String {
}

// Class that collects and manages errors and warnings
// Implemented such that it can be shared immutably. This makes many operations to do with parsing easier
#[derive(Debug,Clone)]
pub struct ErrorCollector {
pub errors : Vec<ParsingError>,
errors : RefCell<Vec<ParsingError>>,
pub file : FileUUID
}

impl ErrorCollector {
pub fn new(file : FileUUID) -> Self {
Self{errors : Vec::new(), file}
Self{errors : RefCell::new(Vec::new()), file}
}

pub fn error_basic<S : Into<String>>(&mut self, position : Span, reason : S) {
self.errors.push(ParsingError{position, reason : reason.into(), infos : Vec::new()});
pub fn error_basic<S : Into<String>>(&self, position : Span, reason : S) {
self.errors.borrow_mut().push(ParsingError{position, reason : reason.into(), infos : Vec::new()});
}

pub fn error_with_info<S : Into<String>>(&mut self, position : Span, reason : S, infos : Vec<ErrorInfo>) {
self.errors.push(ParsingError{position, reason : reason.into(), infos : infos});
pub fn error_with_info<S : Into<String>>(&self, position : Span, reason : S, infos : Vec<ErrorInfo>) {
self.errors.borrow_mut().push(ParsingError{position, reason : reason.into(), infos : infos});
}

pub fn get(self) -> (Vec<ParsingError>, FileUUID) {
(self.errors.into_inner(), self.file)
}
}
Loading

0 comments on commit 758b3d6

Please sign in to comment.