A lot of changes, working on everything

This commit is contained in:
DOOME1M8Cover 2023-06-24 04:16:35 +01:00
parent de2d228143
commit 9eebd7675c
30 changed files with 440 additions and 111 deletions

8
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

13
.idea/comline-rs.iml Normal file
View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/comline-rs.iml" filepath="$PROJECT_DIR$/.idea/comline-rs.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -1,2 +1,7 @@
# comline-rs
# Comline
Comline(Communication on Line) is a library
## Language details
Rust

View file

@ -0,0 +1,44 @@
# Intermediate Representation Generation
When compiling a schema, the schemas imported within it and details
like metadata, state and so on are written into a lockfile `state.lock`
This lockfile will contain freezed information about evertyhing to be worried,
the goal being to preserve relations, state, versioning of the schema(and related
schemas) past and present
Upon locking, any changes made to any of the schemas and their relations, the state
and the differential changes are tracked, and at the same time automatic version and
state changes will be recorded
## Version State
Versioning follows SemVer (Semantic Versioning)
When adding new fields to a any of the [Components](#Components), the minor version
will be increased by 1 in the minor segment
When making any change to an existing field in any of the [Components](#Components), the
major version will be increaded by 1 in the major segment
**IMPORTANT TODO**: This makes `schema.ids` not need indexing manually anywhere,
so the convention `#1 optional ...` where `#1` is indexing, can be removed entirely
(if the system above is defined to substitute this feature, thread carefully)
**NOTE TODO**: The idea of a lockfile is to create state freezing, it can be
a specific IR unit format of itself, or maybe a Json one? decide this
### Components
A component is any part of the schema that does declarations, such being:
- namespace
- constant
- settings
- structure
- enum
- error
- validator
- protocol

View file

@ -9,10 +9,13 @@ settings {
allow-debugging=true
}
settings MailSettings(struct, protocol) {
@affects=struct protocol
settings MailSettings {
indexed=true
}
@settings=MailSettings
struct Mail {
1# sender: str

View file

@ -3,45 +3,59 @@ namespace examples.thing.simple
const AGREEMENT_KEY: string = "agreement_key"
validator StringBounds min_chars=0 max_chars=1024 {
@min_chars=0 max_chars=1024
validator StringBounds {
assert_error(
value.length > params.max_chars or value.length < params.min_chars,
"String {value.name} must be more than {params.min_chars} and less than {params.max_chars}"
)
}
validator PasswordCheck min_chars=16 max_chars=60 {
assert_validate(StringBounds(min_chars=params.min_chars max_chars=params.max_chars)
@min_chars=16 max_chars=60
validator PasswordCheck {
assert_valid(
self.parameters.0,
StringBounds(min_chars=params.min_chars max_chars=params.max_chars
)
}
@settings(versioned=False validate_fields=False)
struct Credentials {
@validators([StringBounds(min_chars=8 max_chars=16)])
1# username: str = "test"
@validators=[PasswordCheck()]
@validators=[PasswordCheck]
2# password: str
}
struct CredentialsOther {
#1 username: union (
str [validators=[StringBounds(min_chars=8 max_chars=16]],
null
) = "test" | null
#2 password: str [validators=[PasswordCheck()]]
struct CredentialsOther {
@parameters.0.validators=[StringBounds(min_chars=8 max_chars=16]
#1 username: union(str null) = "test" | null
@validators=([PasswordCheck()])
#2 password: str
}
enum RegisterStatus {
Ok
UsernameTaken
}
error TellBackError back="Foo" {
message = "Could not get the provider to tell \"{back}\" back"
error TellBackError {
message = "Could not get the provider to tell \"{self.back}\" back"
1# back: str
}
protocol Registry provider=Server {
@provider=Server
protocol Registry {
@argument.0.username.validate=true
#timeout_ms=100
@ -56,12 +70,14 @@ protocol Registry provider=Server {
}
struct TellBackResponse {
}
@
protocol Events provider=Server {
@provider=Server
protocol Events {
async function poke()
}

View file

@ -1,5 +1,5 @@
/*
trait Registry {
fn register(message: Credentials) -> RegisterStatus;
fn my_username() -> String;
@ -18,4 +18,7 @@ struct RegisterStatus {
struct TellBackError {
}
*/
fn main() { todo!() }

View file

@ -1 +1,3 @@
pub mod pest;
pub mod parser;
pub mod constants;

8
src/idl/constants.rs Normal file
View file

@ -0,0 +1,8 @@
// Standard Uses
// Local Uses
// External Uses
pub const SCHEMA_EXTENSION: &str = "ids";
pub const UNIT_EXTENSION: &str = "idu";

View file

@ -1,26 +1,49 @@
// IDL grammar
schema = _{ namespace ~ (COMMENT | settings | constant | validator | enumeration | structure | error | protocol)* }
namespace = { "namespace" ~ WS ~ domain ~ WS }
constant = { "const" ~ WS ~ id ~ WS? ~ ":" ~ WS ~ kind ~ WS ~ ("=" ~ WS ~ value)? ~ WS? }
settings = {
"settings" ~ WS? ~ id? ~ WS? ~
"{" ~ WS? ~ parameter* ~ WS? ~"}"
~ WS?
schema = _{
namespace
~ (
COMMENT | import
| settings | constant
| validator | enumeration
| structure | error | protocol
)*
}
enumeration = {
"enum" ~ WS ~ id ~ WS? ~ parameter* ~ WS? ~
"{" ~ WS? ~ enum_variant+ ~ WS? ~ "}"
namespace = {
"namespace" ~ WS ~ domain
}
import = {
WS ~ "import" ~ WS
~ domain_namespaced
}
constant = {
WS ~ "const" ~ WS ~ id
~ WS? ~ ":" ~ WS?
~ kind ~ (WS? ~ "=" ~ WS? ~ value)?
}
settings = {
WS ~ parameter*
~ "settings" ~ WS? ~ id? ~ WS?
~ "{" ~ WS? ~ parameter* ~ WS? ~ "}"
}
enumeration = {
WS ~ parameter*
~ "enum" ~ WS ~ id ~ WS?
~ "{" ~ WS? ~ enum_variant+ ~ WS? ~ "}"
~ WS?
}
enum_variant = { digit+ ~ WS? ~ "#" ~ WS ~ id ~ WS? }
enum_variant = {
(index ~ "#")? ~ WS? ~ id ~ WS?
}
validator = {
"validator" ~ WS ~ id ~ WS? ~ parameter* ~ WS? ~
"{" ~ WS? ~ function_call* ~ WS? ~ "}"
WS ~ parameter*
~ "validator" ~ WS ~ id ~ WS?
~ "{" ~ WS? ~ function_call* ~ WS? ~ "}"
~ WS?
}
@ -31,22 +54,11 @@ expression = {
(operation ~ WS? ~ boolean_operator? ~ WS?)+
}
function_call = {
id ~ WS? ~ "(" ~ WS? ~
(","? ~ WS? ~ function_call_arg)*
id ~ WS? ~ "(" ~ WS?
~ (","? ~ WS? ~ function_call_arg)*
~ WS? ~ ")" ~ WS?
}
function_call_arg = {
expression | string_interpolated
}
string_interpolated = {
"\"" ~
(string | WS |
("{" ~ domain ~ "}"))*
~ "\""
}
string = @{ (alpha | digit | WS+)+ }
function_call_arg = { expression | string }
entity = { digit+ | domain }
operation = {
@ -55,69 +67,131 @@ operation = {
}
operator = {
"==" | "!=" | "<" | ">" | "+" | "-" | "/" | "|"
"==" | "!="
| "<" | ">"
| "+" | "-" | "/"
| "|"
}
boolean_operator = {
"or" | "and"
}
structure = {
"struct" ~ WS ~ id ~ WS? ~ parameter* ~ WS? ~
"{" ~ WS? ~ (constant | field)+ ~ WS? ~ "}"
WS? ~ parameter*
~ "struct" ~ WS ~ id ~ WS?
~ "{" ~ WS? ~ (constant | field)+ ~ WS? ~ "}"
~ WS?
}
field = {
(index ~ "#")? ~ (WS? ~ requirement)? ~
WS? ~ id ~ WS? ~ ":" ~ WS? ~ kind ~
(WS? ~ "=" ~ WS? ~ value)? ~ WS?
WS? ~ property*
~ (index ~ "#")? ~ (WS? ~ requirement)?
~ WS? ~ id ~ WS? ~ ":" ~ WS? ~ kind
~ (WS? ~ "=" ~ WS? ~ value)? ~ WS?
}
index = { digit }
index = @{ digit }
requirement = { "optional" }
error = {
"error" ~ WS ~ id ~ WS? ~ parameter* ~ WS? ~
"{" ~ WS? ~ (parameter | field)+ ~ WS? ~ "}" ~ WS?
WS? ~ property*
~ "error" ~ WS ~ id ~ WS?
~ "{" ~ WS?
~ (parameter | field)+
~ WS? ~ "}" ~ WS?
}
protocol = {
"protocol" ~ WS ~ id ~ WS? ~ parameter* ~ WS? ~
"{" ~ WS? ~ function+ ~ "}" ~ WS?
WS? ~ property* ~ WS?
~ "protocol" ~ WS ~ id ~ WS?
~ "{" ~ WS? ~ function* ~ WS? ~ "}"
}
function = {
(index ~ WS? ~ "#" ~ WS?)? ~
(asynchronous ~ WS?)? ~
(direction ~ WS?)? ~
"function" ~ WS ~ id ~ WS? ~
"(" ~ WS? ~ argument* ~ WS? ~ ")" ~ WS? ~
("->" ~ WS? ~ returns+ ~ WS?)? ~
(":" ~ WS? ~ parameter+ ~ WS?)? ~
("!" ~ WS? ~ throw+ ~ WS?)? ~
WS?
WS? ~ property* ~ WS?
~ (index ~ WS? ~ "#" ~ WS?)?
~ (asynchronous ~ WS?)?
~ (direction ~ WS?)?
~ "function" ~ WS ~ id ~ WS?
~ "(" ~ WS? ~ argument* ~ WS? ~ ")"
~ (WS? ~ "->" ~ WS? ~ returns+)?
~ (WS? ~ ":" ~ WS? ~ parameter+)?
~ (WS? ~ "!" ~ WS? ~ throw+)?
}
direction = { "client" | "server" }
asynchronous = { "async" }
argument = {
","? ~ WS? ~
((id ~ WS? ~ ":" ~ WS? ~ kind) | kind)
","? ~ WS?
~ ((id ~ WS? ~ ":" ~ WS? ~ kind) | kind)
~ WS?
}
returns = { ","? ~ WS? ~ (kind) ~ WS? }
parameter = {
","? ~ WS? ~ id ~ WS? ~ "=" ~ WS? ~ value ~ WS?
WS? ~ id ~ WS? ~ "=" ~ WS? ~ value ~ WS?
}
throw = {
","? ~ WS? ~ id ~ WS?
","? ~ WS? ~ value ~ WS?
}
// Common Rules
property = {
WS? ~ "@" ~ WS? ~ domain ~ WS? ~ "="
~ (
domain_namespaced | domain
| number | property_array
)
~ (NEWLINE | WS)*
}
property_array = {
"[" ~ property_instance* ~ "]"
}
property_instance = {
(NEWLINE | WS)*
~ domain
~ "(" ~ property_attribute* ~ ")"
~ (NEWLINE | WS)*
}
property_attribute = {
(NEWLINE | WS)*
~ id ~ "=" ~ kind
}
domain = @{ (id | ".")+ }
domain_namespaced = @{ (alpha | "::" | "_")+ }
number = @{ digit+ }
id = @{ (alpha | "_")+ }
kind = @{ (alpha | digit)+ }
// Replace text with match anything inside " "
value = { ("\"" ~ inner_string ~ "\"") | inner_namespaced }
inner_string = @{ (alpha | digit | WS | "{" | "}" | ".")+ }
inner_namespaced = @{ (alpha | digit | "::")+ }
instantiation = {
(domain | domain_namespaced)
~ "(" ~ domain ~ ")"
}
value = {
"true" | "false"
| string | string_interpolated
| instantiation
| domain | domain_namespaced
}
string = {
"\"" ~ string_inner ~ "\""
}
string_interpolated = {
"f" ~ "\"" ~ string_interpolated_inner ~ "\""
}
string_interpolated_inner = _{
(string_interpolation | char)*
}
string_interpolation = _{ "{" ~ domain ~ "}" }
string_inner = _{ (string_interpolation | char)* }
char = {
!("\"" | "\\") ~ ANY
| "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t")
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4})
}
alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }

36
src/idl/parser.rs Normal file
View file

@ -0,0 +1,36 @@
// Standard Uses
// Local Uses
use crate::ir::new_unit::Unit;
// External Uses
use anyhow::Result;
use pest::iterators::Pair;
#[derive(Parser)]
#[grammar = "idl/idl.pest"]
pub struct IDLParser;
/*
pub fn parse_into_unit(content: &str) -> Result<Vec<Unit>> {
let pairs = IDLParser::parse(Rule::schema, content)?;
let mut units = vec![];
for pair in pairs { units.push(parse_inner(pair).unwrap()) }
Ok(units)
}
#[allow(unused)]
pub fn parse_inner(pairs: Pair<Rule>) -> Result<Unit> {
match pairs.as_rule() {
Rule::schema {
},
}
}
*/

View file

@ -3,7 +3,11 @@
// Local Uses
use crate::ir::primitive;
use crate::ir::primitive::TypeValue;
use crate::ir::unit::{Argument, Const, Direction, Enum, EnumVariant, Error, Field, Function, Parameter, Protocol, Settings, Struct, Unit};
use crate::ir::unit::{
Argument, Const, Direction, Enum, EnumVariant,
Error, Field, Function, Parameter,
Protocol, Settings, Struct, Unit
};
// External Uses
use anyhow::Result;

View file

@ -3,4 +3,6 @@ mod sanitizer;
mod context;
mod serialization;
pub mod unit;
pub mod new_unit;
pub mod primitive;
pub mod compiler;

7
src/ir/compiler.rs Normal file
View file

@ -0,0 +1,7 @@
// Standard Uses
// Local Uses
// External Uses

78
src/ir/new_unit.rs Normal file
View file

@ -0,0 +1,78 @@
// Standard Uses
// Local Uses
use crate::ir::primitive::{Primitive, TypeValue};
// External Uses
pub type OrderIndex = u16;
#[derive(Debug, Eq, PartialEq)]
pub enum Direction { Client, Server, Both }
#[derive(Debug, Eq, PartialEq)]
pub enum Unit {
Schema {
tag: String,
namespace: String,
imports: Vec<String>,
constants: Vec<Unit>,
settings: Vec<Unit>,
enums: Vec<Unit>,
structures: Vec<Unit>,
validators: Vec<Unit>,
errors: Vec<Unit>,
protocols: Vec<Unit>
},
Constant {
name: String,
kind: String,
default_value: String,
},
Enum {
name: String,
},
Property {
name: String,
values: Vec<String>
},
Settings {
name: String,
parameters: Vec<Unit>,
},
Struct {
name: String,
parameters: Vec<Unit>,
functions: Vec<Unit>
},
Protocol {
name: String,
parameters: Vec<Unit>,
functions: Vec<Unit>
},
Function {
index: OrderIndex,
name: String,
synchronous: bool,
direction: Direction,
arguments: Vec<Unit>,
returns: Vec<Unit>,
throws: Vec<Unit>
},
Error {
name: String,
parameters: Vec<Unit>,
fields: Vec<Unit>
},
Field {
index: OrderIndex,
}
}
pub enum UnitIndex {
Source(String),
}

View file

@ -19,7 +19,7 @@ pub enum Unit {
Structs(Vec<Struct>),
Enums(Vec<Enum>),
Errors(Vec<Error>),
Protocols(Vec<Protocol>),
Protocols(Vec<Protocol>)
}

View file

@ -3,13 +3,16 @@
// Local Uses
// External Uses
use comline_rs::idl;
use comline_rs::ir::unit::Unit;
use comline::idl;
use comline::idl::constants::SCHEMA_EXTENSION;
use comline::ir::unit::Unit;
#[test]
fn from_raw_to_unit() {
let raw = std::fs::read_to_string("tests/idl/simple.cls").unwrap();
let raw = std::fs::read_to_string(
format!("tests/idl/simple.{}", SCHEMA_EXTENSION)
).unwrap();
let unit = idl::pest::parse_into_unit(raw.as_str()).unwrap();
assert_eq!(

View file

@ -1,22 +0,0 @@
namespace tests.idl.simple
const DEFAULT_NAME: str = "flower"
settings Test {
forbid_optional_indexing=True
}
struct Message {
1# name: str = DEFAULT_NAME
2# optional recipient: str[validators=StringBounds(min_chars=3 max_chars=12)] = "bee"
}
error RecipientNotFoundError {
message = "Recipient with name {self.recipient} not found"
1# recipient: str[validators=StringBounds(min_chars=8 max_chars=16)]
}
protocol Mail provider=Both {
1# function send_message(message: Message) -> str ! NotFoundError[function.message.recipient]
: timeout_ms=1000
}

31
tests/idl/simple.ids Normal file
View file

@ -0,0 +1,31 @@
namespace tests.idl.simple
const POWER: u8 = 10
const DEFAULT_NAME: str = f"flower {POWER}"
settings Test {
forbid_optional_indexing=True
}
struct Message {
1# name: str = DEFAULT_NAME
@validators=[StringBounds(min_chars=3 max_chars=12)]
2# optional recipient: str = "bee"
}
error RecipientNotFoundError {
message = f"Recipient with name {self.recipient} not found"
@validators=[StringBounds(min_chars=8 max_chars=16)]
1# recipient: str
}
@provider=Any
protocol Mail {
@timeout_ms=1000
1# function send_message(message: Message) -> str
! RecipientNotFoundError(function.message.recipient)
}

View file

@ -4,14 +4,14 @@ const PROTOCOL: u8 = 0
const SECRET: u8 = 1
enum Motion {
1 # Wave
2 # MoveArm
1# Wave
2# MoveArm
}
struct Hello {
const SHAKE: u8 = 20
1 # name: u8
1# name: u8
}
struct Goodbye versioned=false {
@ -22,6 +22,6 @@ protocol Greet {
function smile
function wave ()
function wave_wait () -> u8
function wave_and_go () -> str: timeout_ms=100
function wave_and_go () -> str : timeout_ms=100
function wave_with (motion: Motion)
}

View file

@ -5,8 +5,8 @@ use std::string::ToString;
// External Uses
use once_cell::sync::Lazy;
use comline_rs::ir::unit::{Const, Unit};
use comline_rs::ir::primitive::TypeValue;
use comline::ir::unit::{Const, Unit};
use comline::ir::primitive::TypeValue;
// Unit with a namespace and a constant