use crate::parser::{reports::Report, syntax_tree::*};
use crate::config::{EvCall, EvSource, EvType, FnCall, NumTy};
use lalrpop_util::ParseError;
grammar;
extern {
type Error = Report<'input>;
}
match {
r"\s*" => { },
r"(--\[\[[^(\]\])]*\]\])|(--.*)" => { },
} else {
_
}
pub Config: SyntaxConfig<'input> = {
<start:@L> <opts:Opt*> <decls:Decl*> <end:@R> => SyntaxConfig { start, opts, decls, end },
}
Opt: SyntaxOpt<'input> = {
<start:@L> "opt" <name:Identifier> "=" <value:OptValue> ";"? <end:@R> => SyntaxOpt { start, name, value, end },
}
OptValue: SyntaxOptValue<'input> = {
<start:@L> <kind:OptValueKind> <end:@R> => SyntaxOptValue { start, kind, end },
}
OptValueKind: SyntaxOptValueKind<'input> = {
StrLit => SyntaxOptValueKind::Str(<>),
NumLit => SyntaxOptValueKind::Num(<>),
BoolLit => SyntaxOptValueKind::Bool(<>),
}
Decl: SyntaxDecl<'input> = {
<decl:TyDecl> => SyntaxDecl::Ty(decl),
<decl:EvDecl> => SyntaxDecl::Ev(decl),
<decl:FnDecl> => SyntaxDecl::Fn(decl),
}
FnDecl: SyntaxFnDecl<'input> = {
<start:@L> "funct" <name:Identifier> "=" "{"
"call" ":" <call:FnCall>
<args:("," "args" ":" <Ty>)?>
<rets:("," "rets" ":" <Ty>)?>
","?
"}" ";"? <end:@R> => SyntaxFnDecl { start, name, call, args, rets, end },
}
FnCall: FnCall = {
"Async" => FnCall::Async,
"Sync" => FnCall::Sync,
}
EvDecl: SyntaxEvDecl<'input> = {
<start:@L> "event" <name:Identifier> "=" "{"
"from" ":" <from:EvSource>
"," "type" ":" <evty:EvTy>
"," "call" ":" <call:EvCall>
<data:("," "data" ":" <Ty>)?>
","?
"}" ";"? <end:@R> => SyntaxEvDecl { start, name, from, evty, call, data, end },
}
EvCall: EvCall = {
"SingleSync" => EvCall::SingleSync,
"SingleAsync" => EvCall::SingleAsync,
"ManySync" => EvCall::ManySync,
"ManyAsync" => EvCall::ManyAsync,
}
EvTy: EvType = {
"Reliable" => EvType::Reliable,
"Unreliable" => EvType::Unreliable,
}
EvSource: EvSource = {
"Server" => EvSource::Server,
"Client" => EvSource::Client,
}
TyDecl: SyntaxTyDecl<'input> = {
<start:@L> "type" <name:Identifier> "=" <ty:Ty> ";"? <end:@R> => SyntaxTyDecl { start, name, ty, end },
}
Ty: SyntaxTy<'input> = {
<start:@L> <kind:TyKind> <end:@R> => SyntaxTy { start, kind, end },
}
TyKind: SyntaxTyKind<'input> = {
"f32" <r:("(" <NumRange> ")")?> => SyntaxTyKind::Num(NumTy::F32, r),
"f64" <r:("(" <NumRange> ")")?> => SyntaxTyKind::Num(NumTy::F64, r),
"i8" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::I8, r),
"i16" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::I16, r),
"i32" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::I32, r),
"u8" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::U8, r),
"u16" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::U16, r),
"u32" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Num(NumTy::U32, r),
"string" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Str(r),
"buffer" <r:("(" <IntRange> ")")?> => SyntaxTyKind::Buf(r),
<ty:Ty> "[" <r:IntRange?> "]" => SyntaxTyKind::Arr(Box::new(ty), r),
"map" "{" "[" <k:Ty> "]" ":" <v:Ty> "}" => SyntaxTyKind::Map(Box::new(k), Box::new(v)),
<ty:Ty> "?" => SyntaxTyKind::Opt(Box::new(ty)),
<name:Identifier> => SyntaxTyKind::Ref(name),
"enum" <e:Enum> => SyntaxTyKind::Enum(e),
"struct" <s:Struct> => SyntaxTyKind::Struct(s),
"Instance" <c:("(" <Identifier> ")")?> => SyntaxTyKind::Instance(c),
}
Enum: SyntaxEnum<'input> = {
<start:@L> <kind:EnumKind> <end:@R> => SyntaxEnum { start, kind, end },
}
EnumKind: SyntaxEnumKind<'input> = {
"{" <enumerators:Comma<Identifier>> "}" => SyntaxEnumKind::Unit(enumerators),
<tag:StrLit> "{" <mut variants:(<Identifier> <Struct> ",")*> <lv:(<Identifier> <Struct>)?> "}" =>
SyntaxEnumKind::Tagged {
tag,
variants: match lv {
Some(lv) => { variants.push(lv); variants },
None => variants,
},
catch_all: None
},
<tag:StrLit> "{" <variants:(<Identifier> <Struct> ",")*> <ca:("..." <Struct> ","?)> "}" =>
SyntaxEnumKind::Tagged {
tag,
variants,
catch_all: Some(ca),
},
}
Struct: SyntaxStruct<'input> = {
<start:@L> "{" <fields:Comma<(<Identifier> ":" <Ty>)>> "}" <end:@R> => SyntaxStruct { start, fields, end },
}
IntRange: SyntaxRange<'input> = {
<start:@L> <kind:IntRangeKind> <end:@R> => SyntaxRange { start, kind, end },
}
IntRangeKind: SyntaxRangeKind<'input> = {
".." => SyntaxRangeKind::None,
<n:IntLit> => SyntaxRangeKind::Exact(n),
<min:IntLit> ".." => SyntaxRangeKind::WithMin(min),
".." <max:IntLit> => SyntaxRangeKind::WithMax(max),
<min:IntLit> ".." <max:IntLit> => SyntaxRangeKind::WithMinMax(min, max),
}
NumRange: SyntaxRange<'input> = {
<start:@L> <kind:NumRangeKind> <end:@R> => SyntaxRange { start, kind, end },
}
NumRangeKind: SyntaxRangeKind<'input> = {
".." => SyntaxRangeKind::None,
<n:NumLit> => SyntaxRangeKind::Exact(n),
<min:NumLit> ".." => SyntaxRangeKind::WithMin(min),
".." <max:NumLit> => SyntaxRangeKind::WithMax(max),
<min:NumLit> ".." <max:NumLit> => SyntaxRangeKind::WithMinMax(min, max),
}
StrLit: SyntaxStrLit<'input> = {
<start:@L> <value:r#""[^"]*""#> <end:@R> => SyntaxStrLit { start, value, end },
<start:@L> <value:r"'[^']*'"> <end:@R> => SyntaxStrLit { start, value, end },
}
IntLit: SyntaxNumLit<'input> = {
<n:NumLit> =>? {
if n.value.contains('.') {
Err(ParseError::User {
error: Report::ParserExpectedInt { span: n.span() }
})
} else {
Ok(n)
}
}
}
NumLit: SyntaxNumLit<'input> = {
<start:@L> <value:r"-?\d+(\.\d+)?"> <end:@R> => SyntaxNumLit { start, value, end },
}
BoolLit: SyntaxBoolLit = {
<start:@L> "true" <end:@R> => SyntaxBoolLit { start, value: true, end },
<start:@L> "false" <end:@R> => SyntaxBoolLit { start, value: false, end },
}
Identifier: SyntaxIdentifier<'input> = {
<start:@L> <name:r"[a-zA-Z_][a-zA-Z0-9_]*"> <end:@R> => SyntaxIdentifier { start, name, end },
<start:@L> "data" <end:@R> => SyntaxIdentifier { start, name: "data", end },
<start:@L> "event" <end:@R> => SyntaxIdentifier { start, name: "event", end },
<start:@L> "type" <end:@R> => SyntaxIdentifier { start, name: "type", end },
<start:@L> "opt" <end:@R> => SyntaxIdentifier { start, name: "opt", end },
<start:@L> "from" <end:@R> => SyntaxIdentifier { start, name: "from", end },
<start:@L> "call" <end:@R> => SyntaxIdentifier { start, name: "call", end },
<start:@L> "Async" <end:@R> => SyntaxIdentifier { start, name: "Async", end },
<start:@L> "Sync" <end:@R> => SyntaxIdentifier { start, name: "Sync", end },
<start:@L> "Reliable" <end:@R> => SyntaxIdentifier { start, name: "Reliable", end },
<start:@L> "Unreliable" <end:@R> => SyntaxIdentifier { start, name: "Unreliable", end },
<start:@L> "Server" <end:@R> => SyntaxIdentifier { start, name: "Server", end },
<start:@L> "Client" <end:@R> => SyntaxIdentifier { start, name: "Client", end },
<start:@L> "SingleSync" <end:@R> => SyntaxIdentifier { start, name: "SingleSync", end },
<start:@L> "SingleAsync" <end:@R> => SyntaxIdentifier { start, name: "SingleAsync", end },
<start:@L> "ManySync" <end:@R> => SyntaxIdentifier { start, name: "ManySync", end },
<start:@L> "ManyAsync" <end:@R> => SyntaxIdentifier { start, name: "ManyAsync", end },
<start:@L> "enum" <end:@R> => SyntaxIdentifier { start, name: "enum", end },
<start:@L> "struct" <end:@R> => SyntaxIdentifier { start, name: "struct", end },
<start:@L> "map" <end:@R> => SyntaxIdentifier { start, name: "map", end },
<start:@L> "true" <end:@R> => SyntaxIdentifier { start, name: "true", end },
<start:@L> "false" <end:@R> => SyntaxIdentifier { start, name: "false", end },
}
Comma<T>: Vec<T> = {
<mut v:(<T> ",")*> <e:T?> => match e {
Some(e) => { v.push(e); v },
None => v,
}
}