Add required array element constraints
This commit is contained in:
@@ -50,6 +50,9 @@ pub enum Expr {
|
|||||||
Ident(String),
|
Ident(String),
|
||||||
Object(Vec<Field>),
|
Object(Vec<Field>),
|
||||||
Array(Vec<ExprId>),
|
Array(Vec<ExprId>),
|
||||||
|
ArrayConstraint {
|
||||||
|
item: ExprId,
|
||||||
|
},
|
||||||
Let {
|
Let {
|
||||||
bindings: Vec<Field>,
|
bindings: Vec<Field>,
|
||||||
body: ExprId,
|
body: ExprId,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub fn normalize_constraints(
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> crate::Result<Vec<ConstraintEntry>> {
|
) -> crate::Result<Vec<ConstraintEntry>> {
|
||||||
let mut primitive: Option<(PrimitiveType, Span)> = None;
|
let mut primitive: Option<(PrimitiveType, Span)> = None;
|
||||||
|
let mut array_span: Option<Span> = None;
|
||||||
let mut lower: Option<(Bound, Span)> = None;
|
let mut lower: Option<(Bound, Span)> = None;
|
||||||
let mut upper: Option<(Bound, Span)> = None;
|
let mut upper: Option<(Bound, Span)> = None;
|
||||||
let mut rest = Vec::new();
|
let mut rest = Vec::new();
|
||||||
@@ -61,6 +62,13 @@ pub fn normalize_constraints(
|
|||||||
constraint: Constraint::Regex(pattern),
|
constraint: Constraint::Regex(pattern),
|
||||||
span: entry.span,
|
span: entry.span,
|
||||||
}),
|
}),
|
||||||
|
Constraint::ArrayItems(item) => {
|
||||||
|
array_span.get_or_insert(entry.span);
|
||||||
|
rest.push(ConstraintEntry {
|
||||||
|
constraint: Constraint::ArrayItems(item),
|
||||||
|
span: entry.span,
|
||||||
|
});
|
||||||
|
}
|
||||||
Constraint::BuiltinPredicate(name) => rest.push(ConstraintEntry {
|
Constraint::BuiltinPredicate(name) => rest.push(ConstraintEntry {
|
||||||
constraint: Constraint::BuiltinPredicate(name),
|
constraint: Constraint::BuiltinPredicate(name),
|
||||||
span: entry.span,
|
span: entry.span,
|
||||||
@@ -68,12 +76,37 @@ pub fn normalize_constraints(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let (Some((_, primitive_span)), Some(array_span)) = (primitive, array_span) {
|
||||||
|
return Err(Diagnostic::new(
|
||||||
|
DiagnosticKind::Conflict,
|
||||||
|
span,
|
||||||
|
"array element constraints conflict with primitive type constraints",
|
||||||
|
)
|
||||||
|
.with_label(primitive_span, "primitive type constraint")
|
||||||
|
.with_label(array_span, "array element constraint"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(array_span) = array_span
|
||||||
|
&& (lower.is_some() || upper.is_some())
|
||||||
|
{
|
||||||
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
DiagnosticKind::Conflict,
|
||||||
|
span,
|
||||||
|
"numeric comparison constraints conflict with array element constraints",
|
||||||
|
)
|
||||||
|
.with_label(array_span, "array element constraint");
|
||||||
|
if let Some((_, lower_span)) = lower {
|
||||||
|
diagnostic = diagnostic.with_label(lower_span, "numeric comparison constraint");
|
||||||
|
}
|
||||||
|
if let Some((_, upper_span)) = upper {
|
||||||
|
diagnostic = diagnostic.with_label(upper_span, "numeric comparison constraint");
|
||||||
|
}
|
||||||
|
return Err(diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
if matches!(
|
if matches!(
|
||||||
primitive,
|
primitive,
|
||||||
Some((
|
Some((PrimitiveType::String | PrimitiveType::Bool, _))
|
||||||
PrimitiveType::String | PrimitiveType::Bool | PrimitiveType::Array,
|
|
||||||
_
|
|
||||||
))
|
|
||||||
) && (lower.is_some() || upper.is_some())
|
) && (lower.is_some() || upper.is_some())
|
||||||
{
|
{
|
||||||
let mut diagnostic = Diagnostic::new(
|
let mut diagnostic = Diagnostic::new(
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ pub enum HostValue {
|
|||||||
Float(f64),
|
Float(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Array(Vec<HostValue>),
|
Array(Vec<HostValue>),
|
||||||
|
ArrayConstraint {
|
||||||
|
item: Box<HostValue>,
|
||||||
|
constraints: Vec<Constraint>,
|
||||||
|
default: Option<Box<HostValue>>,
|
||||||
|
},
|
||||||
Object(Vec<HostField>),
|
Object(Vec<HostField>),
|
||||||
Abstract {
|
Abstract {
|
||||||
constraints: Vec<Constraint>,
|
constraints: Vec<Constraint>,
|
||||||
@@ -91,8 +96,12 @@ impl HostValue {
|
|||||||
Self::abstract_with_constraint(Constraint::Type(PrimitiveType::Bool))
|
Self::abstract_with_constraint(Constraint::Type(PrimitiveType::Bool))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn array_type() -> Self {
|
pub fn array_of(item: HostValue) -> Self {
|
||||||
Self::abstract_with_constraint(Constraint::Type(PrimitiveType::Array))
|
Self::ArrayConstraint {
|
||||||
|
item: Box::new(item),
|
||||||
|
constraints: Vec::new(),
|
||||||
|
default: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn builtin_predicate(name: impl Into<String>) -> Self {
|
pub fn builtin_predicate(name: impl Into<String>) -> Self {
|
||||||
@@ -109,6 +118,7 @@ impl HostValue {
|
|||||||
pub fn with_constraint(mut self, constraint: Constraint) -> Self {
|
pub fn with_constraint(mut self, constraint: Constraint) -> Self {
|
||||||
match &mut self {
|
match &mut self {
|
||||||
Self::Abstract { constraints, .. } => constraints.push(constraint),
|
Self::Abstract { constraints, .. } => constraints.push(constraint),
|
||||||
|
Self::ArrayConstraint { constraints, .. } => constraints.push(constraint),
|
||||||
_ => {
|
_ => {
|
||||||
self = Self::Abstract {
|
self = Self::Abstract {
|
||||||
constraints: alloc::vec![constraint],
|
constraints: alloc::vec![constraint],
|
||||||
@@ -143,6 +153,22 @@ impl HostValue {
|
|||||||
|
|
||||||
pub fn default(self, value: HostValue) -> Result<Self> {
|
pub fn default(self, value: HostValue) -> Result<Self> {
|
||||||
match self {
|
match self {
|
||||||
|
Self::ArrayConstraint {
|
||||||
|
item,
|
||||||
|
constraints,
|
||||||
|
default: None,
|
||||||
|
} => Ok(Self::ArrayConstraint {
|
||||||
|
item,
|
||||||
|
constraints,
|
||||||
|
default: Some(Box::new(value)),
|
||||||
|
}),
|
||||||
|
Self::ArrayConstraint {
|
||||||
|
default: Some(_), ..
|
||||||
|
} => Err(Diagnostic::new(
|
||||||
|
DiagnosticKind::DefaultConflict,
|
||||||
|
Span::default(),
|
||||||
|
"host value already has a default",
|
||||||
|
)),
|
||||||
Self::Abstract {
|
Self::Abstract {
|
||||||
constraints,
|
constraints,
|
||||||
default: None,
|
default: None,
|
||||||
|
|||||||
+234
-32
@@ -111,9 +111,12 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
ConcreteValue::Bool(value) => Ok(Data::Bool(*value)),
|
ConcreteValue::Bool(value) => Ok(Data::Bool(*value)),
|
||||||
ConcreteValue::Array(items) => {
|
ConcreteValue::Array(items) => {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
for item in items {
|
for (index, item) in items.iter().enumerate() {
|
||||||
let value = self.force(*item)?;
|
let value = self.force(*item)?;
|
||||||
data.push(self.materialize_with_path(&value, path)?);
|
path.push(format!("[{index}]"));
|
||||||
|
let value = self.materialize_with_path(&value, path);
|
||||||
|
path.pop();
|
||||||
|
data.push(value?);
|
||||||
}
|
}
|
||||||
Ok(Data::Array(data))
|
Ok(Data::Array(data))
|
||||||
}
|
}
|
||||||
@@ -158,13 +161,14 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
};
|
};
|
||||||
let default_span = self.thunk_span(default);
|
let default_span = self.thunk_span(default);
|
||||||
let value = self.force(default)?;
|
let value = self.force(default)?;
|
||||||
self.ensure_satisfies(
|
let value = self
|
||||||
&value,
|
.apply_constraints(
|
||||||
&abstract_value.constraints,
|
value,
|
||||||
default_span,
|
&abstract_value.constraints,
|
||||||
Some((default_span, "default value checked here")),
|
default_span,
|
||||||
)
|
Some((default_span, "default value checked here")),
|
||||||
.map_err(|diag| self.with_path_context(diag, "materializing", path))?;
|
)
|
||||||
|
.map_err(|diag| self.with_path_context(diag, "materializing", path))?;
|
||||||
self.materialize_with_path(&value, path)
|
self.materialize_with_path(&value, path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,6 +266,22 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
.collect();
|
.collect();
|
||||||
Ok(RuntimeValue::Concrete(ConcreteValue::Array(thunks)))
|
Ok(RuntimeValue::Concrete(ConcreteValue::Array(thunks)))
|
||||||
}
|
}
|
||||||
|
Expr::ArrayConstraint { item } => {
|
||||||
|
let item = self.add_expr_thunk(
|
||||||
|
ExprRef {
|
||||||
|
module: reference.module,
|
||||||
|
expr: item,
|
||||||
|
},
|
||||||
|
env,
|
||||||
|
);
|
||||||
|
Ok(RuntimeValue::Abstract(AbstractValue {
|
||||||
|
constraints: vec![ConstraintEntry {
|
||||||
|
constraint: Constraint::ArrayItems(item),
|
||||||
|
span,
|
||||||
|
}],
|
||||||
|
default: None,
|
||||||
|
}))
|
||||||
|
}
|
||||||
Expr::Let { bindings, body } => {
|
Expr::Let { bindings, body } => {
|
||||||
let let_env = self.new_env(Some(env));
|
let let_env = self.new_env(Some(env));
|
||||||
for binding in bindings {
|
for binding in bindings {
|
||||||
@@ -550,6 +570,13 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
if let Some(thunk) = self.lookup(env, name) {
|
if let Some(thunk) = self.lookup(env, name) {
|
||||||
return self.force(thunk);
|
return self.force(thunk);
|
||||||
}
|
}
|
||||||
|
if name == "Array" {
|
||||||
|
return Err(Diagnostic::new(
|
||||||
|
DiagnosticKind::UnresolvedIdentifier,
|
||||||
|
span,
|
||||||
|
"`Array` is not a valid constraint; use an element constraint such as `[...String]`",
|
||||||
|
));
|
||||||
|
}
|
||||||
if name.chars().next().is_some_and(char::is_uppercase) {
|
if name.chars().next().is_some_and(char::is_uppercase) {
|
||||||
return Ok(RuntimeValue::Abstract(AbstractValue {
|
return Ok(RuntimeValue::Abstract(AbstractValue {
|
||||||
constraints: vec![ConstraintEntry {
|
constraints: vec![ConstraintEntry {
|
||||||
@@ -697,7 +724,10 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
match self.expr(pattern).clone() {
|
match self.expr(pattern).clone() {
|
||||||
Expr::Wildcard => Ok(true),
|
Expr::Wildcard => Ok(true),
|
||||||
Expr::CompareConstraint { .. } | Expr::RegexConstraint(_) | Expr::Ident(_) => {
|
Expr::ArrayConstraint { .. }
|
||||||
|
| Expr::CompareConstraint { .. }
|
||||||
|
| Expr::RegexConstraint(_)
|
||||||
|
| Expr::Ident(_) => {
|
||||||
let constraint = self.eval_expr(pattern, env)?;
|
let constraint = self.eval_expr(pattern, env)?;
|
||||||
match constraint {
|
match constraint {
|
||||||
RuntimeValue::Abstract(abstract_value) => self
|
RuntimeValue::Abstract(abstract_value) => self
|
||||||
@@ -738,13 +768,12 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
}
|
}
|
||||||
(RuntimeValue::Abstract(abstract_value), concrete @ RuntimeValue::Concrete(_))
|
(RuntimeValue::Abstract(abstract_value), concrete @ RuntimeValue::Concrete(_))
|
||||||
| (concrete @ RuntimeValue::Concrete(_), RuntimeValue::Abstract(abstract_value)) => {
|
| (concrete @ RuntimeValue::Concrete(_), RuntimeValue::Abstract(abstract_value)) => {
|
||||||
self.ensure_satisfies(
|
self.apply_constraints(
|
||||||
&concrete,
|
concrete,
|
||||||
&abstract_value.constraints,
|
&abstract_value.constraints,
|
||||||
span,
|
span,
|
||||||
Some((span, "concrete value being composed here")),
|
Some((span, "concrete value being composed here")),
|
||||||
)?;
|
)
|
||||||
Ok(concrete)
|
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
RuntimeValue::Concrete(ConcreteValue::Object(lhs)),
|
RuntimeValue::Concrete(ConcreteValue::Object(lhs)),
|
||||||
@@ -830,24 +859,35 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
value_label: Option<(Span, &'static str)>,
|
value_label: Option<(Span, &'static str)>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for constraint in constraints {
|
self.apply_constraints(value.clone(), constraints, span, value_label)
|
||||||
self.satisfies(value, constraint, span, value_label)?;
|
.map(|_| ())
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn satisfies(
|
fn apply_constraints(
|
||||||
&mut self,
|
&mut self,
|
||||||
value: &RuntimeValue,
|
mut value: RuntimeValue,
|
||||||
|
constraints: &[ConstraintEntry],
|
||||||
|
span: Span,
|
||||||
|
value_label: Option<(Span, &'static str)>,
|
||||||
|
) -> Result<RuntimeValue> {
|
||||||
|
for constraint in constraints {
|
||||||
|
value = self.apply_constraint(value, constraint, span, value_label)?;
|
||||||
|
}
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_constraint(
|
||||||
|
&mut self,
|
||||||
|
value: RuntimeValue,
|
||||||
constraint: &ConstraintEntry,
|
constraint: &ConstraintEntry,
|
||||||
span: Span,
|
span: Span,
|
||||||
value_label: Option<(Span, &'static str)>,
|
value_label: Option<(Span, &'static str)>,
|
||||||
) -> Result<()> {
|
) -> Result<RuntimeValue> {
|
||||||
let constraint_value = &constraint.constraint;
|
let constraint_value = &constraint.constraint;
|
||||||
match constraint_value {
|
match constraint_value {
|
||||||
Constraint::Type(primitive) => {
|
Constraint::Type(primitive) => {
|
||||||
if value_matches_primitive(value, *primitive) {
|
if value_matches_primitive(&value, *primitive) {
|
||||||
Ok(())
|
Ok(value)
|
||||||
} else {
|
} else {
|
||||||
Err(self.constraint_violation(
|
Err(self.constraint_violation(
|
||||||
constraint,
|
constraint,
|
||||||
@@ -857,8 +897,41 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Constraint::Compare(op, expected) => compare_value(value, *op, expected)
|
Constraint::ArrayItems(item_constraint) => {
|
||||||
.then_some(())
|
let RuntimeValue::Concrete(ConcreteValue::Array(items)) = value else {
|
||||||
|
return Err(self.constraint_violation(
|
||||||
|
constraint,
|
||||||
|
span,
|
||||||
|
value_label,
|
||||||
|
"value does not satisfy array element constraint",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let item_constraint_value = self.force(*item_constraint)?;
|
||||||
|
let mut constrained_items = Vec::with_capacity(items.len());
|
||||||
|
for (index, item) in items.into_iter().enumerate() {
|
||||||
|
let item_span = self.thunk_span(item);
|
||||||
|
let item_value = self.force(item)?;
|
||||||
|
let constrained = self
|
||||||
|
.compose_and(item_constraint_value.clone(), item_value, item_span)
|
||||||
|
.map_err(|diagnostic| {
|
||||||
|
diagnostic
|
||||||
|
.with_label(
|
||||||
|
constraint.span,
|
||||||
|
"array element constraint declared here",
|
||||||
|
)
|
||||||
|
.with_label(
|
||||||
|
item_span,
|
||||||
|
format!("array element [{index}] checked here"),
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
constrained_items.push(self.add_value_thunk_with_span(constrained, item_span));
|
||||||
|
}
|
||||||
|
Ok(RuntimeValue::Concrete(ConcreteValue::Array(
|
||||||
|
constrained_items,
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
Constraint::Compare(op, expected) => compare_value(&value, *op, expected)
|
||||||
|
.then_some(value)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
self.constraint_violation(
|
self.constraint_violation(
|
||||||
constraint,
|
constraint,
|
||||||
@@ -868,14 +941,15 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
Constraint::Regex(pattern) => {
|
Constraint::Regex(pattern) => {
|
||||||
satisfies_regex(value, pattern, constraint.span).map_err(|diag| {
|
satisfies_regex(&value, pattern, constraint.span).map_err(|diag| {
|
||||||
let diag = diag.with_label(constraint.span, "regex constraint declared here");
|
let diag = diag.with_label(constraint.span, "regex constraint declared here");
|
||||||
if let Some((span, message)) = value_label {
|
if let Some((span, message)) = value_label {
|
||||||
diag.with_label(span, message)
|
diag.with_label(span, message)
|
||||||
} else {
|
} else {
|
||||||
diag
|
diag
|
||||||
}
|
}
|
||||||
})
|
})?;
|
||||||
|
Ok(value)
|
||||||
}
|
}
|
||||||
Constraint::BuiltinPredicate(name) => Err(Diagnostic::new(
|
Constraint::BuiltinPredicate(name) => Err(Diagnostic::new(
|
||||||
DiagnosticKind::UnsupportedFeature,
|
DiagnosticKind::UnsupportedFeature,
|
||||||
@@ -940,6 +1014,33 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
}
|
}
|
||||||
Ok(RuntimeValue::Concrete(ConcreteValue::Array(thunks)))
|
Ok(RuntimeValue::Concrete(ConcreteValue::Array(thunks)))
|
||||||
}
|
}
|
||||||
|
HostValue::ArrayConstraint {
|
||||||
|
item,
|
||||||
|
mut constraints,
|
||||||
|
default,
|
||||||
|
} => {
|
||||||
|
let item = self.internalize_host_value(*item)?;
|
||||||
|
let item = self.add_value_thunk(item);
|
||||||
|
let default = if let Some(default) = default {
|
||||||
|
let value = self.internalize_host_value(*default)?;
|
||||||
|
Some(self.add_value_thunk(value))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
constraints.push(Constraint::ArrayItems(item));
|
||||||
|
let constraints = constraints
|
||||||
|
.into_iter()
|
||||||
|
.map(|constraint| ConstraintEntry {
|
||||||
|
constraint,
|
||||||
|
span: Span::default(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let constraints = normalize_constraints(constraints, Span::default())?;
|
||||||
|
Ok(RuntimeValue::Abstract(AbstractValue {
|
||||||
|
constraints,
|
||||||
|
default,
|
||||||
|
}))
|
||||||
|
}
|
||||||
HostValue::Object(fields) => {
|
HostValue::Object(fields) => {
|
||||||
let mut object = ObjectValue { fields: Vec::new() };
|
let mut object = ObjectValue { fields: Vec::new() };
|
||||||
for field in fields {
|
for field in fields {
|
||||||
@@ -1147,7 +1248,7 @@ impl<L: SourceLoader> Engine<L> {
|
|||||||
diagnostic
|
diagnostic
|
||||||
} else {
|
} else {
|
||||||
let span = diagnostic.span;
|
let span = diagnostic.span;
|
||||||
diagnostic.with_label(span, format!("while {phase} `{}`", path.join(".")))
|
diagnostic.with_label(span, format!("while {phase} `{}`", format_path(path)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1170,7 +1271,6 @@ fn primitive_type(name: &str) -> Option<PrimitiveType> {
|
|||||||
"Int" => Some(PrimitiveType::Int),
|
"Int" => Some(PrimitiveType::Int),
|
||||||
"Float" => Some(PrimitiveType::Float),
|
"Float" => Some(PrimitiveType::Float),
|
||||||
"Bool" => Some(PrimitiveType::Bool),
|
"Bool" => Some(PrimitiveType::Bool),
|
||||||
"Array" => Some(PrimitiveType::Array),
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1251,13 +1351,25 @@ fn value_matches_primitive(value: &RuntimeValue, primitive: PrimitiveType) -> bo
|
|||||||
) | (
|
) | (
|
||||||
RuntimeValue::Concrete(ConcreteValue::Bool(_)),
|
RuntimeValue::Concrete(ConcreteValue::Bool(_)),
|
||||||
PrimitiveType::Bool
|
PrimitiveType::Bool
|
||||||
) | (
|
|
||||||
RuntimeValue::Concrete(ConcreteValue::Array(_)),
|
|
||||||
PrimitiveType::Array
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_path(path: &[String]) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
for part in path {
|
||||||
|
if part.starts_with('[') {
|
||||||
|
output.push_str(part);
|
||||||
|
} else {
|
||||||
|
if !output.is_empty() {
|
||||||
|
output.push('.');
|
||||||
|
}
|
||||||
|
output.push_str(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "regex")]
|
#[cfg(feature = "regex")]
|
||||||
fn satisfies_regex(value: &RuntimeValue, pattern: &str, span: Span) -> Result<()> {
|
fn satisfies_regex(value: &RuntimeValue, pattern: &str, span: Span) -> Result<()> {
|
||||||
let RuntimeValue::Concrete(ConcreteValue::String(value)) = value else {
|
let RuntimeValue::Concrete(ConcreteValue::String(value)) = value else {
|
||||||
@@ -1678,6 +1790,96 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraint_accepts_matching_items() {
|
||||||
|
let data = eval_data("[...(Int & >= 1)] & [1, 2, 3]");
|
||||||
|
assert_eq!(
|
||||||
|
data,
|
||||||
|
Data::Array(vec![Data::Int(1), Data::Int(2), Data::Int(3)])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraint_accepts_empty_array() {
|
||||||
|
let data = eval_data("[...Int] & []");
|
||||||
|
assert_eq!(data, Data::Array(vec![]));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraints_compose_per_item() {
|
||||||
|
let data = eval_data("[...Int] & [...> 0] & [1, 2, 3]");
|
||||||
|
assert_eq!(
|
||||||
|
data,
|
||||||
|
Data::Array(vec![Data::Int(1), Data::Int(2), Data::Int(3)])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nested_array_constraints_validate_recursively() {
|
||||||
|
let data = eval_data(r#"[...[...String]] & [["api"], [], ["worker"]]"#);
|
||||||
|
assert_eq!(
|
||||||
|
data,
|
||||||
|
Data::Array(vec![
|
||||||
|
Data::Array(vec![Data::String(String::from("api"))]),
|
||||||
|
Data::Array(vec![]),
|
||||||
|
Data::Array(vec![Data::String(String::from("worker"))]),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraint_rejects_invalid_item_with_index() {
|
||||||
|
let parsed = parse_source("[...Int] & [1, \"two\", 3]").unwrap();
|
||||||
|
let mut engine = Engine::from_parse(parsed.ast, parsed.root);
|
||||||
|
let error = engine.eval_root().unwrap_err();
|
||||||
|
assert_eq!(error.kind, DiagnosticKind::ConstraintViolation);
|
||||||
|
assert!(
|
||||||
|
error
|
||||||
|
.labels
|
||||||
|
.iter()
|
||||||
|
.any(|label| label.message.contains("array element [1]"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraint_applies_object_defaults() {
|
||||||
|
let data = eval_data(
|
||||||
|
r#"
|
||||||
|
[...{
|
||||||
|
name = String;
|
||||||
|
enabled = Bool default true;
|
||||||
|
}] & [{ name = "api"; }]
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
let Data::Array(items) = data else { panic!() };
|
||||||
|
let Data::Object(fields) = &items[0] else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
assert_eq!(fields[0].value, Data::String(String::from("api")));
|
||||||
|
assert_eq!(fields[1].value, Data::Bool(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_constraint_validates_default_array() {
|
||||||
|
let data = eval_data("[...String] default [\"api\", \"worker\"]");
|
||||||
|
assert_eq!(
|
||||||
|
data,
|
||||||
|
Data::Array(vec![
|
||||||
|
Data::String(String::from("api")),
|
||||||
|
Data::String(String::from("worker")),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn removed_array_primitive_reports_migration() {
|
||||||
|
let parsed = parse_source("Array").unwrap();
|
||||||
|
let mut engine = Engine::from_parse(parsed.ast, parsed.root);
|
||||||
|
let error = engine.eval_root().unwrap_err();
|
||||||
|
assert_eq!(error.kind, DiagnosticKind::UnresolvedIdentifier);
|
||||||
|
assert!(error.message.contains("[...String]"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn array_concat_has_lower_precedence_than_arithmetic() {
|
fn array_concat_has_lower_precedence_than_arithmetic() {
|
||||||
let data = eval_data("[1 + 1] ++ [2 * 2]");
|
let data = eval_data("[1 + 1] ++ [2 * 2]");
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub enum TokenKind {
|
|||||||
Semicolon,
|
Semicolon,
|
||||||
Comma,
|
Comma,
|
||||||
Dot,
|
Dot,
|
||||||
|
Ellipsis,
|
||||||
Colon,
|
Colon,
|
||||||
Equal,
|
Equal,
|
||||||
EqualEqual,
|
EqualEqual,
|
||||||
@@ -141,7 +142,18 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
b'.' => {
|
b'.' => {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
TokenKind::Dot
|
if self.consume(b'.') {
|
||||||
|
if self.consume(b'.') {
|
||||||
|
TokenKind::Ellipsis
|
||||||
|
} else {
|
||||||
|
return Err(Diagnostic::syntax(
|
||||||
|
self.span(start, self.pos),
|
||||||
|
"expected third '.' in ellipsis",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TokenKind::Dot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
b':' => {
|
b':' => {
|
||||||
self.pos += 1;
|
self.pos += 1;
|
||||||
@@ -432,4 +444,13 @@ mod tests {
|
|||||||
assert_eq!(tokens[3].kind, TokenKind::Amp);
|
assert_eq!(tokens[3].kind, TokenKind::Amp);
|
||||||
assert_eq!(tokens[4].kind, TokenKind::Gte);
|
assert_eq!(tokens[4].kind, TokenKind::Gte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tokenizes_array_constraint_ellipsis() {
|
||||||
|
let tokens = Lexer::new("[...String]").tokenize().unwrap();
|
||||||
|
assert_eq!(tokens[0].kind, TokenKind::LBracket);
|
||||||
|
assert_eq!(tokens[1].kind, TokenKind::Ellipsis);
|
||||||
|
assert!(matches!(tokens[2].kind, TokenKind::Ident(_)));
|
||||||
|
assert_eq!(tokens[3].kind, TokenKind::RBracket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -338,6 +338,17 @@ impl Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_array_after_lbracket(&mut self, start_span: Span) -> Result<ExprId> {
|
fn parse_array_after_lbracket(&mut self, start_span: Span) -> Result<ExprId> {
|
||||||
|
if self.consume_kind(&TokenKind::Ellipsis).is_some() {
|
||||||
|
let item = self.parse_expr(0)?;
|
||||||
|
let _ = self.consume_kind(&TokenKind::Comma);
|
||||||
|
self.expect_kind(
|
||||||
|
&TokenKind::RBracket,
|
||||||
|
"expected ']' after array element constraint",
|
||||||
|
)?;
|
||||||
|
let span = start_span.join(self.previous_span());
|
||||||
|
return Ok(self.ast.push(Expr::ArrayConstraint { item }, span));
|
||||||
|
}
|
||||||
|
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
if self.consume_kind(&TokenKind::RBracket).is_some() {
|
if self.consume_kind(&TokenKind::RBracket).is_some() {
|
||||||
return Ok(self
|
return Ok(self
|
||||||
@@ -674,4 +685,18 @@ mod tests {
|
|||||||
};
|
};
|
||||||
assert_eq!(fields[0].path, ["feature", "enable"]);
|
assert_eq!(fields[0].path, ["feature", "enable"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_array_constraint() {
|
||||||
|
let parsed = parse_source("[...(String & /^api-/)]").unwrap();
|
||||||
|
let Expr::ArrayConstraint { item } = parsed.ast.get(parsed.root).expr else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
assert!(matches!(parsed.ast.get(item).expr, Expr::Binary { .. }));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_array_constraint_without_element_constraint() {
|
||||||
|
assert!(parse_source("[...]").is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ pub struct ConstraintEntry {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum Constraint {
|
pub enum Constraint {
|
||||||
Type(PrimitiveType),
|
Type(PrimitiveType),
|
||||||
|
ArrayItems(ThunkId),
|
||||||
Compare(CompareOp, LiteralValue),
|
Compare(CompareOp, LiteralValue),
|
||||||
Regex(String),
|
Regex(String),
|
||||||
BuiltinPredicate(String),
|
BuiltinPredicate(String),
|
||||||
@@ -79,7 +80,6 @@ pub enum PrimitiveType {
|
|||||||
Int,
|
Int,
|
||||||
Float,
|
Float,
|
||||||
Bool,
|
Bool,
|
||||||
Array,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
|||||||
@@ -198,9 +198,9 @@ impl IntoHostValue for bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> DecodalSchema for Vec<T> {
|
impl<T: DecodalSchema> DecodalSchema for Vec<T> {
|
||||||
fn decodal_schema() -> HostValue {
|
fn decodal_schema() -> HostValue {
|
||||||
HostValue::array_type()
|
HostValue::array_of(T::decodal_schema())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,18 @@ struct Service {
|
|||||||
tags: Vec<String>,
|
tags: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Decodal)]
|
||||||
|
struct Worker {
|
||||||
|
name: String,
|
||||||
|
#[decodal(default = true)]
|
||||||
|
enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Decodal)]
|
||||||
|
struct Fleet {
|
||||||
|
workers: Vec<Worker>,
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn derives_schema_and_decode() {
|
fn derives_schema_and_decode() {
|
||||||
let mut engine = Engine::new(EmptyLoader);
|
let mut engine = Engine::new(EmptyLoader);
|
||||||
@@ -77,3 +89,62 @@ fn decode_reports_field_path() {
|
|||||||
let error = Service::decodal_decode(&data).unwrap_err();
|
let error = Service::decodal_decode(&data).unwrap_err();
|
||||||
assert_eq!(error.path, "name");
|
assert_eq!(error.path, "name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vec_schema_rejects_invalid_element_before_decode() {
|
||||||
|
let mut engine = Engine::new(EmptyLoader);
|
||||||
|
engine
|
||||||
|
.bind_global("Service", Service::decodal_schema())
|
||||||
|
.unwrap();
|
||||||
|
let module = engine
|
||||||
|
.add_root_source(
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
r#"
|
||||||
|
Service & {
|
||||||
|
name = "api";
|
||||||
|
port = 9443;
|
||||||
|
tags = ["web", 1];
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let error = engine.eval_module(module).unwrap_err();
|
||||||
|
assert!(
|
||||||
|
error
|
||||||
|
.labels
|
||||||
|
.iter()
|
||||||
|
.any(|label| label.message.contains("array element [1]"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn vec_schema_applies_nested_struct_defaults() {
|
||||||
|
let mut engine = Engine::new(EmptyLoader);
|
||||||
|
engine
|
||||||
|
.bind_global("Fleet", Fleet::decodal_schema())
|
||||||
|
.unwrap();
|
||||||
|
let module = engine
|
||||||
|
.add_root_source(
|
||||||
|
"test",
|
||||||
|
"test",
|
||||||
|
r#"
|
||||||
|
Fleet & {
|
||||||
|
workers = [{ name = "api"; }];
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let value = engine.eval_module(module).unwrap();
|
||||||
|
let data = engine.materialize(&value).unwrap();
|
||||||
|
let fleet = Fleet::decodal_decode(&data).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
fleet,
|
||||||
|
Fleet {
|
||||||
|
workers: vec![Worker {
|
||||||
|
name: "api".into(),
|
||||||
|
enabled: true,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ impl<'a> Formatter<'a> {
|
|||||||
if expression_contains_comment(node)
|
if expression_contains_comment(node)
|
||||||
&& !matches!(
|
&& !matches!(
|
||||||
node.kind(),
|
node.kind(),
|
||||||
"object" | "array" | "let_expression" | "match_expression"
|
"object" | "array" | "array_constraint" | "let_expression" | "match_expression"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
out.push_str(self.raw_trimmed(node));
|
out.push_str(self.raw_trimmed(node));
|
||||||
@@ -454,6 +454,7 @@ impl<'a> Formatter<'a> {
|
|||||||
"comparison_constraint" => self.write_comparison_constraint(out, node, indent),
|
"comparison_constraint" => self.write_comparison_constraint(out, node, indent),
|
||||||
"object" => self.write_object(out, node, indent),
|
"object" => self.write_object(out, node, indent),
|
||||||
"array" => self.write_array(out, node, indent),
|
"array" => self.write_array(out, node, indent),
|
||||||
|
"array_constraint" => self.write_array_constraint(out, node, indent),
|
||||||
"let_expression" => self.write_let(out, node, indent),
|
"let_expression" => self.write_let(out, node, indent),
|
||||||
"function_expression" => self.write_function(out, node, indent),
|
"function_expression" => self.write_function(out, node, indent),
|
||||||
"match_expression" => self.write_match(out, node, indent),
|
"match_expression" => self.write_match(out, node, indent),
|
||||||
@@ -541,6 +542,14 @@ impl<'a> Formatter<'a> {
|
|||||||
out.push(']');
|
out.push(']');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_array_constraint(&mut self, out: &mut String, node: Node<'a>, indent: usize) {
|
||||||
|
out.push_str("[...");
|
||||||
|
if let Some(element) = node.child_by_field_name("element") {
|
||||||
|
self.write_expr(out, element, indent, 0);
|
||||||
|
}
|
||||||
|
out.push(']');
|
||||||
|
}
|
||||||
|
|
||||||
fn write_let(&mut self, out: &mut String, node: Node<'a>, indent: usize) {
|
fn write_let(&mut self, out: &mut String, node: Node<'a>, indent: usize) {
|
||||||
let body = node.child_by_field_name("body");
|
let body = node.child_by_field_name("body");
|
||||||
out.push_str("let");
|
out.push_str("let");
|
||||||
@@ -797,7 +806,7 @@ fn is_inline_expr(node: Node<'_>) -> bool {
|
|||||||
!expression_contains_comment(node)
|
!expression_contains_comment(node)
|
||||||
&& named_children(node).into_iter().all(is_inline_expr)
|
&& named_children(node).into_iter().all(is_inline_expr)
|
||||||
}
|
}
|
||||||
"array" => {
|
"array" | "array_constraint" => {
|
||||||
!expression_contains_comment(node)
|
!expression_contains_comment(node)
|
||||||
&& named_children(node).into_iter().all(is_inline_expr)
|
&& named_children(node).into_iter().all(is_inline_expr)
|
||||||
}
|
}
|
||||||
@@ -842,6 +851,16 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn formats_array_constraints() {
|
||||||
|
let source = "tags=[...String];ports=[...(Int&>=1)];";
|
||||||
|
let formatted = format_source(source).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
formatted,
|
||||||
|
"tags = [...String];\nports = [...(Int & >= 1)];\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn wasm_export_returns_json() {
|
fn wasm_export_returns_json() {
|
||||||
let output = format_source_json("value={a=1;};");
|
let output = format_source_json("value={a=1;};");
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ let / function env
|
|||||||
```
|
```
|
||||||
|
|
||||||
Module top-level bindings shadow prelude bindings.
|
Module top-level bindings shadow prelude bindings.
|
||||||
Primitive type names such as `String`, `Int`, `Float`, `Bool`, and `Array` are handled before environment lookup, so they are reserved and cannot be shadowed by host bindings.
|
Primitive type names such as `String`, `Int`, `Float`, and `Bool` are handled before environment lookup, so they are reserved and cannot be shadowed by host bindings.
|
||||||
|
|
||||||
## Global bindings
|
## Global bindings
|
||||||
|
|
||||||
@@ -59,12 +59,16 @@ HostValue =
|
|||||||
Float
|
Float
|
||||||
Bool
|
Bool
|
||||||
Array(Vec<HostValue>)
|
Array(Vec<HostValue>)
|
||||||
|
ArrayConstraint { item, constraints, default }
|
||||||
Object(Vec<HostField>)
|
Object(Vec<HostField>)
|
||||||
Abstract { constraints, default }
|
Abstract { constraints, default }
|
||||||
```
|
```
|
||||||
|
|
||||||
When a host value is bound, the engine internalizes it into `RuntimeValue` and allocates value thunks for object fields, array items, and defaults.
|
When a host value is bound, the engine internalizes it into `RuntimeValue` and allocates value thunks for object fields, array items, and defaults.
|
||||||
|
|
||||||
|
`HostValue::array_of(item)` builds an array constraint with a required element schema.
|
||||||
|
There is no host API for an unconstrained abstract array.
|
||||||
|
|
||||||
## Abstract host objects
|
## Abstract host objects
|
||||||
|
|
||||||
A host-provided schema object is represented as a concrete object structure whose fields may contain abstract values.
|
A host-provided schema object is represented as a concrete object structure whose fields may contain abstract values.
|
||||||
|
|||||||
@@ -123,12 +123,16 @@ constraint は concrete value とは別の型として扱う。
|
|||||||
```text
|
```text
|
||||||
Constraint =
|
Constraint =
|
||||||
Type(PrimitiveType)
|
Type(PrimitiveType)
|
||||||
|
ArrayItems(ThunkId)
|
||||||
Compare(Op, Literal)
|
Compare(Op, Literal)
|
||||||
Regex(Pattern)
|
Regex(Pattern)
|
||||||
BuiltinPredicate(Symbol)
|
BuiltinPredicate(Symbol)
|
||||||
ObjectConstraint(...)
|
ObjectConstraint(...)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`ArrayItems` は配列そのものの型と、すべての要素へ合成する schema thunk を表す。
|
||||||
|
配列用の primitive type は持たず、抽象配列には必ず要素制約が必要である。
|
||||||
|
|
||||||
初期実装では、object の形は主に `Concrete(Object)` の field に `Abstract` を置くことで表現する。
|
初期実装では、object の形は主に `Concrete(Object)` の field に `Abstract` を置くことで表現する。
|
||||||
object 全体にかかる constraint は必要になった時点で追加する。
|
object 全体にかかる constraint は必要になった時点で追加する。
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,19 @@ String & /^a$/ & /^b$/
|
|||||||
Host = IPv4Address;
|
Host = IPv4Address;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 配列制約
|
||||||
|
|
||||||
|
配列制約には要素制約が必須であり、`[...T]` と書く。
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
Names = [...String];
|
||||||
|
PositiveInts = [...(Int & > 0)];
|
||||||
|
```
|
||||||
|
|
||||||
|
複数の配列制約を `&` で合成した場合、各 concrete 要素へすべての要素制約を合成する。
|
||||||
|
要素が object schema の場合は、その schema に含まれる default も各要素へ適用される。
|
||||||
|
要素制約のない `Array` primitive type は存在しない。
|
||||||
|
|
||||||
## default
|
## default
|
||||||
|
|
||||||
`default` は制約ではない。
|
`default` は制約ではない。
|
||||||
|
|||||||
@@ -31,6 +31,23 @@ disabled_config = NewConfig & {
|
|||||||
enabled_config = NewConfig;
|
enabled_config = NewConfig;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 配列スキーマ
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
Services = [...{
|
||||||
|
name = String;
|
||||||
|
port = Int default 8080;
|
||||||
|
}];
|
||||||
|
|
||||||
|
Services & [
|
||||||
|
{ name = "api"; },
|
||||||
|
{ name = "worker"; port = 9000; },
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
抽象配列には要素制約が必須である。
|
||||||
|
この例では、1 番目の要素の `port` は `8080` に materialize される。
|
||||||
|
|
||||||
## 関数と制約
|
## 関数と制約
|
||||||
|
|
||||||
```dcdl
|
```dcdl
|
||||||
|
|||||||
@@ -7,6 +7,46 @@ array expression は、順序付きの値の列を表す。
|
|||||||
["a", "b", "c"]
|
["a", "b", "c"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
配列リテラルは concrete value であり、要素型を揃える必要はない。
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
["api", 8080, true]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Array constraint
|
||||||
|
|
||||||
|
配列制約は `[` の直後に ellipsis を置き、その後へ要素制約を記述する。
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
Names = [...String];
|
||||||
|
Ports = [...(Int & >= 1 & <= 65535)];
|
||||||
|
```
|
||||||
|
|
||||||
|
`[...T]` は、すべての要素が `T` を満たす長さ 0 以上の配列を表す。
|
||||||
|
空配列は任意の配列制約を満たす。
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
[...String] & []
|
||||||
|
[...String] & ["api", "worker"]
|
||||||
|
```
|
||||||
|
|
||||||
|
要素制約は object schema にもできる。
|
||||||
|
要素 schema の default は、配列へ制約を合成するときに各要素へ適用される。
|
||||||
|
|
||||||
|
```dcdl
|
||||||
|
Services = [...{
|
||||||
|
name = String;
|
||||||
|
enabled = Bool default true;
|
||||||
|
}];
|
||||||
|
|
||||||
|
Services & [{ name = "api"; }]
|
||||||
|
```
|
||||||
|
|
||||||
|
要素制約のない抽象配列型は提供しない。
|
||||||
|
旧来の `Array` primitive type は使用できず、`[...T]` の `T` は必須である。
|
||||||
|
`[String]` は配列制約ではなく、未解決の `String` 制約を 1 要素に持つ concrete array になる。
|
||||||
|
長さ制約、位置別の tuple 制約、unique 制約は現在サポートしない。
|
||||||
|
|
||||||
## Array concat
|
## Array concat
|
||||||
|
|
||||||
`++` は concrete array 同士を連結する。
|
`++` は concrete array 同士を連結する。
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Expr
|
|||||||
├─ path reference
|
├─ path reference
|
||||||
├─ object
|
├─ object
|
||||||
├─ array
|
├─ array
|
||||||
|
├─ array constraint
|
||||||
├─ function
|
├─ function
|
||||||
├─ function call
|
├─ function call
|
||||||
├─ let
|
├─ let
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ primary_expression = literal
|
|||||||
| identifier
|
| identifier
|
||||||
| comparison_constraint
|
| comparison_constraint
|
||||||
| object
|
| object
|
||||||
|
| array_constraint
|
||||||
| array
|
| array
|
||||||
| let_expression
|
| let_expression
|
||||||
| function_expression
|
| function_expression
|
||||||
@@ -73,6 +74,7 @@ field_definition = field_path , "=" , expression ;
|
|||||||
field_path = identifier , { "." , identifier } ;
|
field_path = identifier , { "." , identifier } ;
|
||||||
|
|
||||||
array = "[" , [ expression , { "," , expression } , [ "," ] ] , "]" ;
|
array = "[" , [ expression , { "," , expression } , [ "," ] ] , "]" ;
|
||||||
|
array_constraint = "[" , "..." , expression , [ "," ] , "]" ;
|
||||||
|
|
||||||
let_expression = "let" , { field_definition , ";" } , "in" , expression ;
|
let_expression = "let" , { field_definition , ";" } , "in" , expression ;
|
||||||
function_expression = "(" , [ parameter_list ] , ")" , "=>" , expression ;
|
function_expression = "(" , [ parameter_list ] , ")" , "=>" , expression ;
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ false
|
|||||||
default fallback 指定
|
default fallback 指定
|
||||||
=> 関数
|
=> 関数
|
||||||
. フィールド参照 / ドットパス定義
|
. フィールド参照 / ドットパス定義
|
||||||
|
... 配列の要素制約
|
||||||
```
|
```
|
||||||
|
|
||||||
演算子の優先順位は [合成演算子](./operators.md) で定義する。
|
演算子の優先順位は [合成演算子](./operators.md) で定義する。
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ name = String;
|
|||||||
retry = Int default 3;
|
retry = Int default 3;
|
||||||
ratio = Float;
|
ratio = Float;
|
||||||
enable = Bool default true;
|
enable = Bool default true;
|
||||||
tags = Array;
|
tags = [...String];
|
||||||
```
|
```
|
||||||
|
|
||||||
現在の primitive type は `String`、`Int`、`Float`、`Bool`、`Array` である。
|
現在の primitive type は `String`、`Int`、`Float`、`Bool` である。
|
||||||
|
配列は primitive type ではなく、必須の要素制約を持つ `[...T]` で表現する。
|
||||||
各型の個別仕様へのリンクは [Manual Index](../../index.md) に集約する。
|
各型の個別仕様へのリンクは [Manual Index](../../index.md) に集約する。
|
||||||
|
|
||||||
primitive type と制約合成の詳細は [制約と default](../constraints-and-defaults.md) も参照する。
|
primitive type と制約合成の詳細は [制約と default](../constraints-and-defaults.md) も参照する。
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ PrimaryExpression {
|
|||||||
Identifier |
|
Identifier |
|
||||||
ComparisonConstraint |
|
ComparisonConstraint |
|
||||||
Object |
|
Object |
|
||||||
|
ArrayConstraint |
|
||||||
Array |
|
Array |
|
||||||
LetExpression |
|
LetExpression |
|
||||||
FunctionExpression |
|
FunctionExpression |
|
||||||
@@ -88,6 +89,7 @@ FieldDefinition { FieldPath Equal Expression }
|
|||||||
FieldPath { Identifier !fieldPath (Dot Identifier)* }
|
FieldPath { Identifier !fieldPath (Dot Identifier)* }
|
||||||
|
|
||||||
Array { LBracket (Expression (Comma Expression)* Comma?)? RBracket }
|
Array { LBracket (Expression (Comma Expression)* Comma?)? RBracket }
|
||||||
|
ArrayConstraint { LBracket Ellipsis Expression Comma? RBracket }
|
||||||
|
|
||||||
LetExpression { Let FieldDefinitionList In Expression }
|
LetExpression { Let FieldDefinitionList In Expression }
|
||||||
FieldDefinitionList { (FieldDefinition Semicolon)* }
|
FieldDefinitionList { (FieldDefinition Semicolon)* }
|
||||||
@@ -143,6 +145,7 @@ ImportExpression { Import String }
|
|||||||
Semicolon { ";" }
|
Semicolon { ";" }
|
||||||
Comma { "," }
|
Comma { "," }
|
||||||
Dot { "." }
|
Dot { "." }
|
||||||
|
Ellipsis { "..." }
|
||||||
Colon { ":" }
|
Colon { ":" }
|
||||||
Equal { "=" }
|
Equal { "=" }
|
||||||
EqualEqual { "==" }
|
EqualEqual { "==" }
|
||||||
|
|||||||
@@ -158,3 +158,27 @@ Array concat
|
|||||||
right: (literal (integer))))
|
right: (literal (integer))))
|
||||||
right: (array
|
right: (array
|
||||||
(literal (integer)))))))
|
(literal (integer)))))))
|
||||||
|
|
||||||
|
==================
|
||||||
|
Array constraints
|
||||||
|
==================
|
||||||
|
{
|
||||||
|
tags = [...String];
|
||||||
|
ports = [...(Int & >= 1),];
|
||||||
|
}
|
||||||
|
---
|
||||||
|
|
||||||
|
(source_file
|
||||||
|
(object
|
||||||
|
(field_definition
|
||||||
|
path: (field_path (identifier))
|
||||||
|
value: (array_constraint
|
||||||
|
element: (identifier)))
|
||||||
|
(field_definition
|
||||||
|
path: (field_path (identifier))
|
||||||
|
value: (array_constraint
|
||||||
|
element: (parenthesized_expression
|
||||||
|
(binary_expression
|
||||||
|
left: (identifier)
|
||||||
|
right: (comparison_constraint
|
||||||
|
value: (integer))))))))
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ module.exports = grammar({
|
|||||||
$.regex_literal,
|
$.regex_literal,
|
||||||
$.comparison_constraint,
|
$.comparison_constraint,
|
||||||
$.object,
|
$.object,
|
||||||
|
$.array_constraint,
|
||||||
$.array,
|
$.array,
|
||||||
$.let_expression,
|
$.let_expression,
|
||||||
$.function_expression,
|
$.function_expression,
|
||||||
@@ -116,6 +117,14 @@ module.exports = grammar({
|
|||||||
']',
|
']',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
array_constraint: $ => seq(
|
||||||
|
'[',
|
||||||
|
'...',
|
||||||
|
field('element', $._expression),
|
||||||
|
optional(','),
|
||||||
|
']',
|
||||||
|
),
|
||||||
|
|
||||||
let_expression: $ => seq(
|
let_expression: $ => seq(
|
||||||
'let',
|
'let',
|
||||||
repeat(seq($.field_definition, ';')),
|
repeat(seq($.field_definition, ';')),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"*"
|
"*"
|
||||||
"/"
|
"/"
|
||||||
"++"
|
"++"
|
||||||
|
"..."
|
||||||
"&&"
|
"&&"
|
||||||
"||"
|
"||"
|
||||||
"!"
|
"!"
|
||||||
|
|||||||
+41
@@ -95,6 +95,10 @@
|
|||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "object"
|
"name": "object"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "array_constraint"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "SYMBOL",
|
"type": "SYMBOL",
|
||||||
"name": "array"
|
"name": "array"
|
||||||
@@ -427,6 +431,43 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"array_constraint": {
|
||||||
|
"type": "SEQ",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "["
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "FIELD",
|
||||||
|
"name": "element",
|
||||||
|
"content": {
|
||||||
|
"type": "SYMBOL",
|
||||||
|
"name": "_expression"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CHOICE",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": ","
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "BLANK"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "STRING",
|
||||||
|
"value": "]"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"let_expression": {
|
"let_expression": {
|
||||||
"type": "SEQ",
|
"type": "SEQ",
|
||||||
"members": [
|
"members": [
|
||||||
|
|||||||
+160
@@ -11,6 +11,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -74,6 +78,86 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true,
|
||||||
|
"fields": {
|
||||||
|
"element": {
|
||||||
|
"multiple": false,
|
||||||
|
"required": true,
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"type": "array",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "binary_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "call_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "comparison_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "default_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "function_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "identifier",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "import_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "let_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "literal",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "match_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "parenthesized_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "path_expression",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "regex_literal",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "unary_expression",
|
||||||
|
"named": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true,
|
"named": true,
|
||||||
@@ -86,6 +170,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -222,6 +310,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -303,6 +395,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -374,6 +470,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -471,6 +571,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -547,6 +651,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -617,6 +725,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -703,6 +815,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -794,6 +910,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -896,6 +1016,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1009,6 +1133,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1083,6 +1211,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1159,6 +1291,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1260,6 +1396,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1346,6 +1486,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1431,6 +1575,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1507,6 +1655,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1586,6 +1738,10 @@
|
|||||||
"type": "array",
|
"type": "array",
|
||||||
"named": true
|
"named": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "array_constraint",
|
||||||
|
"named": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "binary_expression",
|
"type": "binary_expression",
|
||||||
"named": true
|
"named": true
|
||||||
@@ -1712,6 +1868,10 @@
|
|||||||
"type": ".",
|
"type": ".",
|
||||||
"named": false
|
"named": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "...",
|
||||||
|
"named": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "/",
|
"type": "/",
|
||||||
"named": false
|
"named": false
|
||||||
|
|||||||
Generated
+5487
-4941
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
|||||||
|
let
|
||||||
|
Service = {
|
||||||
|
name = String;
|
||||||
|
enabled = Bool default true;
|
||||||
|
};
|
||||||
|
Services = [...Service];
|
||||||
|
in
|
||||||
|
Services & [
|
||||||
|
{ name = "api"; },
|
||||||
|
{ name = "worker"; enabled = false; },
|
||||||
|
]
|
||||||
@@ -2,15 +2,15 @@
|
|||||||
import {LRParser} from "npm:@lezer/lr@^1.4.10"
|
import {LRParser} from "npm:@lezer/lr@^1.4.10"
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
states: "7vQYQPOOO#nQPO'#CaOOQO'#Cr'#CrO$wQPO'#CyO&UQPO'#DOO&^QPO'#DSO&eQPO'#DWO&mQPO'#CqO$wQPO'#DcO&wQPO'#DhOOQO'#Cq'#CqOOQO'#Cp'#CpO&|QPO'#CoO$wQPO'#CoOOQO'#Cn'#CnO)fQPO'#CmO.XQPO'#ClO0]QPO'#CkOOQO'#Cj'#CjO2TQPO'#CiO3xQPO'#ChO5jQPO'#CgO7UQPO'#CfOOQO'#Ce'#CeO7`QPO'#C`O7eQPO'#C_OOQO'#Dz'#DzQYQPOOO8xQPO'#D{O8}QPO,58{OOQO,59e,59eO9VQPO'#CaOOQO,59j,59jO9_QPO,59jOOQO,59n,59nO9gQPO,59nO9oQPO'#EOO9tQPO'#DYO9|QPO,59rO:RQPO'#CqO:`QPO'#D^O:hQQO,59vO:mQPO,59vO:rQPO,59]O:wQPO,59}OOQO,5:S,5:SO:|QPO'#DjOOQO,59[,59[O;TQPO,59[OOQO,59Z,59ZO$wQPO,59YO$wQPO,59XO$wQPO,59WOOQO'#Dr'#DrO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zOOQO,58y,58yOOQO-E7x-E7xOOQO,5:g,5:gOOQO-E7y-E7yO;YQPO1G/UO;bQPO1G/UOOQO1G/U1G/UO;jQPO1G/YO;qQPO1G/YOOQO1G/Y1G/YOOQO,5:j,5:jOOQO-E7|-E7|O$wQPO1G/^O$wQPO,59yO;yQPO,59xO<RQPO,59xO$wQPO1G/bO<ZQQO1G/bOOQO1G.w1G.wO<`QPO1G/iO<jQPO'#DkOOQO,5:U,5:UO<rQPO,5:UOOQO1G.v1G.vOOQO1G.t1G.tO<wQPO1G.sO@_QPO1G.rOAyQPO1G.qOOQO1G.p1G.pOCqQPO1G.oOEfQPO1G.nOFxQPO1G.mOOQO1G.l1G.lOOQO1G.f1G.fOOQO1G.s1G.sOOQO1G.r1G.rOOQO1G.q1G.qOOQO1G.o1G.oOOQO1G.n1G.nOOQO1G.m1G.mOOQO,5:h,5:hOOQO7+$p7+$pOHfQPO7+$pOOQO-E7z-E7zOOQO,5:i,5:iOOQO7+$t7+$tOHnQPO7+$tOOQO-E7{-E7{OOQO7+$x7+$xOOQO1G/e1G/eOHuQPO'#D_OOQO,5:k,5:kOHzQPO1G/dOOQO-E7}-E7}OOQO7+$|7+$|O$wQPO7+$|OOQO'#Df'#DfOISQPO'#DeOOQO7+%T7+%TOIXQPO7+%TOIaQPO,5:VOIhQPO,5:VOOQO1G/p1G/pOOQO<<H[<<H[PIpQPO'#D|OOQO<<H`<<H`P$wQPO'#D}PIuQPO'#EPOOQO<<Hh<<HhO$wQPO,5:POIzQPO<<HoOJUQPO<<HoOOQO<<Ho<<HoOJ^QPO1G/qOOQO1G/k1G/kOOQO,5:l,5:lOOQOAN>ZAN>ZOJeQPOAN>ZOOQO-E8O-E8OOOQOG23uG23uP<cQPO'#EQO$wQPO,59XO$wQPO,59WO$wQPO,59VO$wQPO,59TO$wQPO,59SO$wQPO,59ROJoQPO1G.rOKVQPO'#ClOKjQPO'#CkOL^QPO'#ChOM^QPO'#CgONaQPO'#CfO$wQPO,59WO$wQPO,59UO$wQPO,59QO! jQPO1G.qO!!QQPO'#CkO!#_QPO'#CiO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zO!$[QPO1G.oO!$rQPO1G.nO!%YQPO1G.mO!%zQPO'#CiO!&rQPO'#ChO!'gQPO'#CgO!(XQPO'#CfO!(vQPO'#C`",
|
states: "8fQYQPOOO#nQPO'#CaOOQO'#Cr'#CrO$wQPO'#CyO&UQPO'#DOO&^QQO'#DXO&hQPO'#DYO&pQPO'#CqO$wQPO'#DeO&zQPO'#DjOOQO'#Cq'#CqOOQO'#Cp'#CpO'PQPO'#CoO$wQPO'#CoOOQO'#Cn'#CnO)iQPO'#CmO.[QPO'#ClO0`QPO'#CkOOQO'#Cj'#CjO2WQPO'#CiO3{QPO'#ChO5mQPO'#CgO7XQPO'#CfOOQO'#Ce'#CeO7cQPO'#C`O7hQPO'#C_OOQO'#D|'#D|QYQPOOO8{QPO'#D}O9QQPO,58{OOQO,59e,59eO9YQPO'#CaOOQO,59j,59jO9bQPO,59jO$wQPO,59nOOQO,59s,59sO9jQPO,59sO9rQPO'#EQO9wQPO'#D[O:PQPO,59tO:UQPO'#CqO:cQPO'#D`O:kQQO,59xO:pQPO,59xO:uQPO,59]O:zQPO,5:POOQO,5:U,5:UO;PQPO'#DlOOQO,59[,59[O;WQPO,59[OOQO,59Z,59ZO$wQPO,59YO$wQPO,59XO$wQPO,59WOOQO'#Dt'#DtO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zOOQO,58y,58yOOQO-E7z-E7zOOQO,5:i,5:iOOQO-E7{-E7{O;]QPO1G/UO;eQPO1G/UOOQO1G/U1G/UO;mQPO1G/YO;uQPO1G/_O;|QPO1G/_OOQO1G/_1G/_OOQO,5:l,5:lOOQO-E8O-E8OO$wQPO1G/`O$wQPO,59{O<UQPO,59zO<^QPO,59zO$wQPO1G/dO<fQQO1G/dOOQO1G.w1G.wO<kQPO1G/kO<uQPO'#DmOOQO,5:W,5:WO<}QPO,5:WOOQO1G.v1G.vOOQO1G.t1G.tO=SQPO1G.sO@jQPO1G.rOBUQPO1G.qOOQO1G.p1G.pOC|QPO1G.oOEqQPO1G.nOGTQPO1G.mOOQO1G.l1G.lOOQO1G.f1G.fOOQO1G.s1G.sOOQO1G.r1G.rOOQO1G.q1G.qOOQO1G.o1G.oOOQO1G.n1G.nOOQO1G.m1G.mOOQO,5:j,5:jOOQO7+$p7+$pOHqQPO7+$pOOQO-E7|-E7|OOQO7+$t7+$tOHyQPO7+$tOOQO,5:k,5:kOOQO7+$y7+$yOIOQPO7+$yOOQO-E7}-E7}OOQO7+$z7+$zOOQO1G/g1G/gOIVQPO'#DaOOQO,5:m,5:mOI[QPO1G/fOOQO-E8P-E8POOQO7+%O7+%OO$wQPO7+%OOOQO'#Dh'#DhOIdQPO'#DgOOQO7+%V7+%VOIiQPO7+%VOIqQPO,5:XOIxQPO,5:XOOQO1G/r1G/rOOQO<<H[<<H[PJQQPO'#EOOOQO<<H`<<H`OOQO<<He<<HeP$wQPO'#EPPJVQPO'#EROOQO<<Hj<<HjO$wQPO,5:ROJ[QPO<<HqOJfQPO<<HqOOQO<<Hq<<HqOJnQPO1G/sOOQO1G/m1G/mOOQO,5:n,5:nOOQOAN>]AN>]OJuQPOAN>]OOQO-E8Q-E8QOOQOG23wG23wP<nQPO'#ESO$wQPO,59XO$wQPO,59WO$wQPO,59VO$wQPO,59TO$wQPO,59SO$wQPO,59ROKPQPO1G.rOKgQPO'#ClOKzQPO'#CkOLnQPO'#ChOMnQPO'#CgONqQPO'#CfO$wQPO,59WO$wQPO,59UO$wQPO,59QO! zQPO1G.qO!!bQPO'#CkO!#oQPO'#CiO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zO!$lQPO1G.oO!%SQPO1G.nO!%jQPO1G.mO!&[QPO'#CiO!'SQPO'#ChO!'wQPO'#CgO!(iQPO'#CfO!)WQPO'#C`",
|
||||||
stateData: "!)Y~O!wOSPOS~OUPOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OneXoeXpeXqeX!PeX!aeX!beX!ceX!deX!eeX!geX!heX!ieX!jeX!keX!leX!meX~OVlOUeXWTXgeXheXieXjeXkeXleXseXteXweX{eX!WeX!]eX!`eX!ueX~P!gOUYOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OUoOupO~OyrO~P$wOUoO}|P~OUwO!TyO~P]Og}O~OV!QO!P!OOUcXgcXhcXicXjcXkcXlcXncXocXpcXqcXscXtcXwcX{cX!WcX!]cX!`cX!acX!bcX!ccX!dcX!ecX!gcX!hcX!icX!jcX!kcX!lcX!mcX!ucXxcXycX!TcXucX!ScX~O!b!SO!c!SOUaXgaXhaXiaXjaXkaXlaXnaXoaXpaXqaXsaXtaXwaX{aX!PaX!WaX!]aX!`aX!aaX!daX!eaX!gaX!haX!iaX!jaX!kaX!laX!maX!uaXVaXxaXyaX!TaXuaX!SaX~OU`Xg`Xh`Xi`Xj`Xk`Xl`Xn`Xo`Xp`Xq`Xs`Xt`Xw`X{`X!P`X!W`X!]`X!``X!e`X!g`X!h`X!i`X!j`X!k`X!l`X!m`X!u`Xx`Xy`X!T`Xu`X!S`X~O!a!TO!d!TO~P,OOn!VOo!VOp!VOq!VO!g!VO!h!VOU_Xg_Xh_Xi_Xj_Xk_Xl_Xs_Xt_Xw_X{_X!P_X!W_X!]_X!`_X!a_X!i_X!j_X!k_X!l_X!m_X!u_X~O!e!UO~P.cOU]Xg]Xh]Xi]Xj]Xk]Xl]Xn]Xo]Xp]Xq]Xs]Xt]Xw]X{]X!P]X!W]X!]]X!`]X!a]X!j]X!k]X!l]X!m]X!u]X~O!i!XO~P0dOU[Xg[Xh[Xi[Xj[Xk[Xl[Xn[Xo[Xp[Xq[Xs[Xt[Xw[X{[X!P[X!W[X!][X!`[X!a[X!k[X!l[X!m[X!u[X~O!j!YO~P2[OUZXgZXhZXiZXjZXkZXlZXnZXoZXpZXqZXsZXtZXwZX{ZX!PZX!WZX!]ZX!`ZX!aZX!lZX!mZX!uZX~O!k!ZO~P4POUYXgYXhYXiYXjYXkYXlYXnYXoYXpYXqYXsYXtYXwYX{YX!PYX!WYX!]YX!`YX!aYX!uYX~O!l![O!m!]O~P5qOW!^O~Ot!_OURXgRXhRXiRXjRXkRXlRXnRXoRXpRXqRXsRXwRX{RX!PRX!WRX!]RX!`RX!aRX!uRX~OU!aO~OVlOWTa~OVlOWTX~Ot!cOu!eO~Ox!fOy!hO~Ot!iO~OUoO}|X~O}!kO~O!S!lOVeX!TeX~P!gOx!mO!T!QX~O!U!oO~O!T!pO~O!T!qO~Os!rO~O!T!tO~P$wOU!vO~OUoOu#YO~Ot#ZOu#YO~Oy#^O~P$wOx#_Oy#^O~OU#cO!T!Qa~Ox#eO!T!Qa~O!U#hO~Ou#kO!Z#iO~P$wOx#mO!T!_X~O!T#oO~O!b!SO!c!SOUaigaihaiiaijaikailainaioaipaiqaisaitaiwai{ai!Pai!Wai!]ai!`ai!aai!dai!eai!gai!hai!iai!jai!kai!lai!mai!uaixaiyai!Taiuai!Sai~O!d!TOn`io`ip`iq`is`it`i!e`i!g`i!h`i!i`i!j`i!k`i!l`i!m`i~OU`ig`ih`ii`ij`ik`il`iw`i{`i!P`i!W`i!]`i!``i!a`i!u`i~P?^Os_it_i!i_i!j_i!k_i!l_i!m_i~O!e!UOU_ig_ih_ii_ij_ik_il_in_io_ip_iq_iw_i{_i!P_i!W_i!]_i!`_i!a_i!u_i~PAbOs]it]i!j]i!k]i!l]i!m]i~O!i!XOU]ig]ih]ii]ij]ik]il]in]io]ip]iq]iw]i{]i!P]i!W]i!]]i!`]i!a]i!u]i~PC]Os[it[i!k[i!l[i!m[i~O!j!YOU[ig[ih[ii[ij[ik[il[in[io[ip[iq[iw[i{[i!P[i!W[i!][i!`[i!a[i!u[i~PETO!k!ZOUZigZihZiiZijZikZilZinZioZipZiqZisZitZiwZi{Zi!PZi!WZi!]Zi!`Zi!aZi!lZi!mZi!uZi~OUoOu#pO~Oy#rO~P$wO!S!lO~OU#cO!T!Qi~O!S#vO~Ot#wOu#yO~O!T!_a~P$wOx#zO!T!_a~OUoO~OU#cO~Ou#}O!Z#iO~P$wOt$OOu#}O~O!T!_i~P$wOu$QO!Z#iO~P$wO!a!TOx`iy`i!T`iu`i!S`i~P?^O!a$SO!d$SOV`X!b`X!c`X~P,OO!e$TOV_X!b_X!c_X!d_Xx_Xy_X!T_Xu_X!S_X~P.cO!j$VOV[X!b[X!c[X!d[X!e[X!g[X!h[X!i[Xx[Xy[X!T[Xu[X!S[X~P2[O!k$WOVZX!bZX!cZX!dZX!eZX!gZX!hZX!iZX!jZXxZXyZX!TZXuZX!SZX~P4PO!l$XO!m$bOVYX!bYX!cYX!dYX!eYX!gYX!hYX!iYX!jYX!kYXxYXyYX!TYXuYX!SYX~P5qO!e$`Ox_iy_i!T_iu_i!S_i~PAbOn!VOo!VOp!VOq!VO!e$`O!g!VO!h!VOx_Xy_X!i_X!j_X!k_X!l_X!m_X!T_Xs_Xt_Xu_X!S_X~O!i$aOV]X!b]X!c]X!d]X!e]X!g]X!h]Xx]Xy]X!T]Xu]X!S]X~P0dO!i$gOx]iy]i!T]iu]i!S]i~PC]O!j$hOx[iy[i!T[iu[i!S[i~PETO!k$iOxZiyZi!lZi!mZi!TZisZitZiuZi!SZi~O!i$gOx]Xy]X!j]X!k]X!l]X!m]X!T]Xs]Xt]Xu]X!S]X~O!j$hOx[Xy[X!k[X!l[X!m[X!T[Xs[Xt[Xu[X!S[X~O!k$iOxZXyZX!lZX!mZX!TZXsZXtZXuZX!SZX~O!l$jO!m$kOxYXyYX!TYXsYXtYXuYX!SYX~OW$lO~O{}!W!]!mjkih!ZUj~",
|
stateData: "!)j~O!yOSPOS~OUPOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO}UO!RVO!YWO!_XO!b]O!c]O~OneXoeXpeXqeX!ReX!ceX!deX!eeX!feX!geX!ieX!jeX!keX!leX!meX!neX!oeX~OVlOUeXWTXgeXheXieXjeXkeXleXseXteXweX}eX!YeX!_eX!beX!weX~P!gOUYOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO}UO!RVO!YWO!_XO!b]O!c]O~OUoOupO~OxrOzsO~P$wOUoO!P!OP~OUxO!VzO~P]Og!OO~OV!RO!R!POUcXgcXhcXicXjcXkcXlcXncXocXpcXqcXscXtcXwcX}cX!YcX!_cX!bcX!ccX!dcX!ecX!fcX!gcX!icX!jcX!kcX!lcX!mcX!ncX!ocX!wcXycXzcX!VcXucX!UcX~O!d!TO!e!TOUaXgaXhaXiaXjaXkaXlaXnaXoaXpaXqaXsaXtaXwaX}aX!RaX!YaX!_aX!baX!caX!faX!gaX!iaX!jaX!kaX!laX!maX!naX!oaX!waXVaXyaXzaX!VaXuaX!UaX~OU`Xg`Xh`Xi`Xj`Xk`Xl`Xn`Xo`Xp`Xq`Xs`Xt`Xw`X}`X!R`X!Y`X!_`X!b`X!g`X!i`X!j`X!k`X!l`X!m`X!n`X!o`X!w`Xy`Xz`X!V`Xu`X!U`X~O!c!UO!f!UO~P,ROn!WOo!WOp!WOq!WO!i!WO!j!WOU_Xg_Xh_Xi_Xj_Xk_Xl_Xs_Xt_Xw_X}_X!R_X!Y_X!__X!b_X!c_X!k_X!l_X!m_X!n_X!o_X!w_X~O!g!VO~P.fOU]Xg]Xh]Xi]Xj]Xk]Xl]Xn]Xo]Xp]Xq]Xs]Xt]Xw]X}]X!R]X!Y]X!_]X!b]X!c]X!l]X!m]X!n]X!o]X!w]X~O!k!YO~P0gOU[Xg[Xh[Xi[Xj[Xk[Xl[Xn[Xo[Xp[Xq[Xs[Xt[Xw[X}[X!R[X!Y[X!_[X!b[X!c[X!m[X!n[X!o[X!w[X~O!l!ZO~P2_OUZXgZXhZXiZXjZXkZXlZXnZXoZXpZXqZXsZXtZXwZX}ZX!RZX!YZX!_ZX!bZX!cZX!nZX!oZX!wZX~O!m![O~P4SOUYXgYXhYXiYXjYXkYXlYXnYXoYXpYXqYXsYXtYXwYX}YX!RYX!YYX!_YX!bYX!cYX!wYX~O!n!]O!o!^O~P5tOW!_O~Ot!`OURXgRXhRXiRXjRXkRXlRXnRXoRXpRXqRXsRXwRX}RX!RRX!YRX!_RX!bRX!cRX!wRX~OU!bO~OVlOWTa~OVlOWTX~Ot!dOu!fO~Oy!hOz!jO~Ot!kO~OUoO!P!OX~O!P!mO~O!U!nOVeX!VeX~P!gOy!oO!V!SX~O!W!qO~O!V!rO~O!V!sO~Os!tO~O!V!vO~P$wOU!xO~OUoOu#[O~Ot#]Ou#[O~Oy#`Oz#_O~Oz#bO~P$wOy#cOz#bO~OU#gO!V!Sa~Oy#iO!V!Sa~O!W#lO~Ou#oO!]#mO~P$wOy#qO!V!aX~O!V#sO~O!d!TO!e!TOUaigaihaiiaijaikailainaioaipaiqaisaitaiwai}ai!Rai!Yai!_ai!bai!cai!fai!gai!iai!jai!kai!lai!mai!nai!oai!waiyaizai!Vaiuai!Uai~O!f!UOn`io`ip`iq`is`it`i!g`i!i`i!j`i!k`i!l`i!m`i!n`i!o`i~OU`ig`ih`ii`ij`ik`il`iw`i}`i!R`i!Y`i!_`i!b`i!c`i!w`i~P?iOs_it_i!k_i!l_i!m_i!n_i!o_i~O!g!VOU_ig_ih_ii_ij_ik_il_in_io_ip_iq_iw_i}_i!R_i!Y_i!__i!b_i!c_i!w_i~PAmOs]it]i!l]i!m]i!n]i!o]i~O!k!YOU]ig]ih]ii]ij]ik]il]in]io]ip]iq]iw]i}]i!R]i!Y]i!_]i!b]i!c]i!w]i~PChOs[it[i!m[i!n[i!o[i~O!l!ZOU[ig[ih[ii[ij[ik[il[in[io[ip[iq[iw[i}[i!R[i!Y[i!_[i!b[i!c[i!w[i~PE`O!m![OUZigZihZiiZijZikZilZinZioZipZiqZisZitZiwZi}Zi!RZi!YZi!_Zi!bZi!cZi!nZi!oZi!wZi~OUoOu#tO~Oz#vO~Oz#wO~P$wO!U!nO~OU#gO!V!Si~O!U#{O~Ot#|Ou$OO~O!V!aa~P$wOy$PO!V!aa~OUoO~OU#gO~Ou$SO!]#mO~P$wOt$TOu$SO~O!V!ai~P$wOu$VO!]#mO~P$wO!c!UOy`iz`i!V`iu`i!U`i~P?iO!c$XO!f$XOV`X!d`X!e`X~P,RO!g$YOV_X!d_X!e_X!f_Xy_Xz_X!V_Xu_X!U_X~P.fO!l$[OV[X!d[X!e[X!f[X!g[X!i[X!j[X!k[Xy[Xz[X!V[Xu[X!U[X~P2_O!m$]OVZX!dZX!eZX!fZX!gZX!iZX!jZX!kZX!lZXyZXzZX!VZXuZX!UZX~P4SO!n$^O!o$gOVYX!dYX!eYX!fYX!gYX!iYX!jYX!kYX!lYX!mYXyYXzYX!VYXuYX!UYX~P5tO!g$eOy_iz_i!V_iu_i!U_i~PAmOn!WOo!WOp!WOq!WO!g$eO!i!WO!j!WOy_Xz_X!k_X!l_X!m_X!n_X!o_X!V_Xs_Xt_Xu_X!U_X~O!k$fOV]X!d]X!e]X!f]X!g]X!i]X!j]Xy]Xz]X!V]Xu]X!U]X~P0gO!k$lOy]iz]i!V]iu]i!U]i~PChO!l$mOy[iz[i!V[iu[i!U[i~PE`O!m$nOyZizZi!nZi!oZi!VZisZitZiuZi!UZi~O!k$lOy]Xz]X!l]X!m]X!n]X!o]X!V]Xs]Xt]Xu]X!U]X~O!l$mOy[Xz[X!m[X!n[X!o[X!V[Xs[Xt[Xu[X!U[X~O!m$nOyZXzZX!nZX!oZX!VZXsZXtZXuZX!UZX~O!n$oO!o$pOyYXzYX!VYXsYXtYXuYX!UYX~OW$qO~O}!P!Y!_!ojkih!]Uj~",
|
||||||
goto: "3l!uPPP!v!z#[PPP#h$m%]%}&x'v(w)s*z,S-Y.b/f0jPPPPPP0jPPPP0jPPP0jPPP0jP1nP0jP1q1tPPP0jP1|2UP0jP2[2_PPPPPP2bPPPPPPP2k2q2x3O3Y3`3fTjOkSiOkQqSStUuV#X!c#Z#qShOk]$tSUu!c#Z#qSiOkQnRQsTQ{VQ|WQ!s!OS#Q!^$lY#]!f#_#m#s#zQ#a!kQ#b!lQ#g!oW#i!r#w$O$RQ#u#hR#{#v!OgORTVWk!O!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$lV#P!]$b$kWfOk!]!^Y$_R!k!o#h$bs$sTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lWeOk!]!^Q#O![Q#W$XY$^R!k!o#h$bQ$o$js$rTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lYdOk![!]!^Q!}!ZQ#V$W[$]R!k!o#h$X$bQ$n$iu$qTVW!O!f!l!r#_#m#s#v#w#z$O$R$j$k$l[cOk!Z![!]!^Q!|!YQ#U$V^$eR!k!o#h$W$X$bQ$m$hw$pTVW!O!f!l!r#_#m#s#v#w#z$O$R$i$j$k$l!hbORTVWk!O!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$V$W$X$b$h$i$j$k$lV!{!X$a$g`aOk!X!Y!Z![!]!^Q!z!WQ#T$Ub$[R!k!o#h$V$W$X$a$bQ$c$f{$dTVW!O!f!l!r#_#m#s#v#w#z$O$R$g$h$i$j$k$l!``OTVWk!O!W!X!Y!Z![!]!^!f!l!r#_#m#s#v#w#z$O$R$f$g$h$i$j$k$lQ!y!UQ#S$TQ$Y$`e$ZR!k!o#h$U$V$W$X$a$b!z_ORTVWk!O!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!x!TR#R$S#O^ORTVWk!O!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!R]R!w!S#T[ORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TZORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TYORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lRvURzVQxVV#d!m#e#tQ#l!rV#|#w$O$RX#j!r#w$O$RR!P[R!u!OQ!WaQ$U$[R$f$dQkOR!`kSmPoR!bmQ!dqR#[!dQ!gsS#`!g#nR#n!sQuUR!juQ!nxR#f!nQ#x#lR$P#x",
|
goto: "4O!wPPP!x!|#^PPP#j$r%c&U'Q(P)R*O+W,a-h.q/v0{PPPPPP0{PPPP0{PPP0{PPPP0{0{P2QP0{P2T2WPPP0{P2`2hP0{P2n2qPPPPPP2tPPPPPPP2}3T3[3b3l3r3xTjOkSiOkQqSSuUvV#Z!d#]#uShOk]$ySUv!d#]#uSiOkQnRQtTQ|VQ}WQ!grQ!u!PS#S!_$qY#a!h#c#q#x$PQ#e!mQ#f!nQ#k!qW#m!t#|$T$WQ#z#lR$Q#{!QgORTVWkr!P!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$qV#R!^$g$pWfOk!^!_Y$dR!m!q#l$gu$xTVWr!P!h!n!t#c#q#x#{#|$P$T$W$p$qWeOk!^!_Q#Q!]Q#Y$^Y$cR!m!q#l$gQ$t$ou$wTVWr!P!h!n!t#c#q#x#{#|$P$T$W$p$qYdOk!]!^!_Q#P![Q#X$][$bR!m!q#l$^$gQ$s$nw$vTVWr!P!h!n!t#c#q#x#{#|$P$T$W$o$p$q[cOk![!]!^!_Q#O!ZQ#W$[^$jR!m!q#l$]$^$gQ$r$my$uTVWr!P!h!n!t#c#q#x#{#|$P$T$W$n$o$p$q!jbORTVWkr!P!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$[$]$^$g$m$n$o$p$qV!}!Y$f$l`aOk!Y!Z![!]!^!_Q!|!XQ#V$Zb$aR!m!q#l$[$]$^$f$gQ$h$k}$iTVWr!P!h!n!t#c#q#x#{#|$P$T$W$l$m$n$o$p$q!b`OTVWkr!P!X!Y!Z![!]!^!_!h!n!t#c#q#x#{#|$P$T$W$k$l$m$n$o$p$qQ!{!VQ#U$YQ$_$ee$`R!m!q#l$Z$[$]$^$f$g!|_ORTVWkr!P!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qQ!z!UR#T$X#Q^ORTVWkr!P!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qQ!S]R!y!T#V[ORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$q#VZORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$q#VYORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qRwUR{VQyVV#h!o#i#yQ#p!tV$R#|$T$WX#n!t#|$T$WR!Q[R!w!PQ!XaQ$Z$aR$k$iQkOR!akSmPoR!cmQ!eqR#^!eQ!itS#d!i#rR#r!uQvUR!lvQ!pyR#j!pQ#}#pR$U#}",
|
||||||
nodeNames: "⚠ Comment Source Statement FieldDefinition FieldPath Identifier Dot Equal Expression DefaultExpression PatchExpression ComposeExpression LogicalOrExpression LogicalAndExpression ComparisonExpression ConcatExpression AdditiveExpression MultiplicativeExpression UnaryExpression PostfixExpression PrimaryExpression Literal String Integer Float True False Regex ComparisonConstraint Lt Lte Gt Gte Object LBrace Semicolon RBrace Array LBracket Comma RBracket LetExpression Let FieldDefinitionList In FunctionExpression LParen ParameterList Parameter Colon RParen Arrow MatchExpression Match MatchArm Pattern Underscore ImportExpression Import CallSuffix ArgumentList Bang Minus Star Slash Plus PlusPlus CompareOperator EqualEqual BangEqual AmpAmp PipePipe Amp SlashSlash Default",
|
nodeNames: "⚠ Comment Source Statement FieldDefinition FieldPath Identifier Dot Equal Expression DefaultExpression PatchExpression ComposeExpression LogicalOrExpression LogicalAndExpression ComparisonExpression ConcatExpression AdditiveExpression MultiplicativeExpression UnaryExpression PostfixExpression PrimaryExpression Literal String Integer Float True False Regex ComparisonConstraint Lt Lte Gt Gte Object LBrace Semicolon RBrace ArrayConstraint LBracket Ellipsis Comma RBracket Array LetExpression Let FieldDefinitionList In FunctionExpression LParen ParameterList Parameter Colon RParen Arrow MatchExpression Match MatchArm Pattern Underscore ImportExpression Import CallSuffix ArgumentList Bang Minus Star Slash Plus PlusPlus CompareOperator EqualEqual BangEqual AmpAmp PipePipe Amp SlashSlash Default",
|
||||||
maxTerm: 85,
|
maxTerm: 87,
|
||||||
skippedNodes: [0,1],
|
skippedNodes: [0,1],
|
||||||
repeatNodeCount: 7,
|
repeatNodeCount: 7,
|
||||||
tokenData: "=T~R!PX^$Upq$Uqr$yrs%Wst&zvw'cxy'pyz'uz{'z{|(P|}(^}!O(c!O!P(h!P!Q(m!Q![+T![!]+n!]!^+s!^!_+x!_!`,V!`!a,l!c!},y!}#O-[#P#Q-a#R#S-f#T#W,y#W#X-y#X#Y,y#Y#Z1Z#Z#],y#]#^3k#^#`,y#`#a6}#a#b8b#b#h,y#h#i:r#i#o,y#o#p<n#p#q<s#q#r=O#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~$ZY!w~X^$Upq$U#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~%OP!`~!_!`%R~%WO!h~~%ZWOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t<%lO%W~%xOg~~%{RO;'S%W;'S;=`&U;=`O%W~&XXOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t;=`<%l%W<%lO%W~&wP;=`<%l%W~'PSP~OY&zZ;'S&z;'S;=`']<%lO&z~'`P;=`<%l&z~'hP!k~vw'k~'pO!i~~'uO!P~~'zO!T~~(PO!b~~(UP!d~{|(X~(^O!e~~(cOx~~(hO!a~~(mOV~~(rW!c~OY)[Z!P)[!P!Q+O!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)_WOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)|Ol~~*PRO;'S)[;'S;=`*Y;=`O)[~*]XOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x;=`<%l)[<%lO)[~*{P;=`<%l)[~+TO!l~~+YQh~!O!P+`!Q![+T~+cP!Q![+f~+kPi~!Q![+f~+sO!S~~+xOt~~+}Pn~!_!`,Q~,VOo~~,[QWP!_!`,b!`!a,g~,gO!g~Q,lO!UQ~,qPp~!_!`,t~,yOq~~-OSU~!Q![,y!c!},y#R#S,y#T#o,y~-aOw~~-fOy~~-mS!Z~U~!Q![,y!c!},y#R#S,y#T#o,y~.OUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y.b#Y#o,y~.gUU~!Q![,y!c!},y#R#S,y#T#Y,y#Y#Z.y#Z#o,y~/OTU~!Q![,y!c!},y#R#S,y#T#U/_#U#o,y~/dUU~!Q![,y!c!},y#R#S,y#T#i,y#i#j/v#j#o,y~/{UU~!Q![,y!c!},y#R#S,y#T#`,y#`#a0_#a#o,y~0dUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i0v#i#o,y~0}S!m~U~!Q![,y!c!},y#R#S,y#T#o,y~1`TU~!Q![,y!c!},y#R#S,y#T#U1o#U#o,y~1tUU~!Q![,y!c!},y#R#S,y#T#`,y#`#a2W#a#o,y~2]UU~!Q![,y!c!},y#R#S,y#T#g,y#g#h2o#h#o,y~2tUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y3W#Y#o,y~3_Sk~U~!Q![,y!c!},y#R#S,y#T#o,y~3pVU~!Q![,y!c!},y#R#S,y#T#a,y#a#b4V#b#c6j#c#o,y~4[UU~!Q![,y!c!},y#R#S,y#T#d,y#d#e4n#e#o,y~4sUU~!Q![,y!c!},y#R#S,y#T#c,y#c#d5V#d#o,y~5[UU~!Q![,y!c!},y#R#S,y#T#f,y#f#g5n#g#o,y~5sUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i6V#i#o,y~6^S!]~U~!Q![,y!c!},y#R#S,y#T#o,y~6qS}~U~!Q![,y!c!},y#R#S,y#T#o,y~7SUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y7f#Y#o,y~7kUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i7}#i#o,y~8US{~U~!Q![,y!c!},y#R#S,y#T#o,y~8gTU~!Q![,y!c!},y#R#S,y#T#U8v#U#o,y~8{UU~!Q![,y!c!},y#R#S,y#T#h,y#h#i9_#i#o,y~9dUU~!Q![,y!c!},y#R#S,y#T#V,y#V#W9v#W#o,y~9{UU~!Q![,y!c!},y#R#S,y#T#[,y#[#]:_#]#o,y~:fS!W~U~!Q![,y!c!},y#R#S,y#T#o,y~:wUU~!Q![,y!c!},y#R#S,y#T#f,y#f#g;Z#g#o,y~;`UU~!Q![,y!c!},y#R#S,y#T#i,y#i#j;r#j#o,y~;wUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y<Z#Y#o,y~<bSj~U~!Q![,y!c!},y#R#S,y#T#o,y~<sOs~~<vP#p#q<y~=OO!j~~=TOu~",
|
tokenData: "=c~R!PX^$Upq$Uqr$yrs%Wst&zvw'cxy'pyz'uz{'z{|(P|}(^}!O(c!O!P(h!P!Q({!Q![+c![!]+|!]!^,R!^!_,W!_!`,e!`!a,z!c!}-X!}#O-j#P#Q-o#R#S-t#T#W-X#W#X.X#X#Y-X#Y#Z1i#Z#]-X#]#^3y#^#`-X#`#a7]#a#b8p#b#h-X#h#i;Q#i#o-X#o#p<|#p#q=R#q#r=^#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~$ZY!y~X^$Upq$U#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~%OP!b~!_!`%R~%WO!j~~%ZWOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t<%lO%W~%xOg~~%{RO;'S%W;'S;=`&U;=`O%W~&XXOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t;=`<%l%W<%lO%W~&wP;=`<%l%W~'PSP~OY&zZ;'S&z;'S;=`']<%lO&z~'`P;=`<%l&z~'hP!m~vw'k~'pO!k~~'uO!R~~'zO!V~~(PO!d~~(UP!f~{|(X~(^O!g~~(cOy~~(hO!c~R(mPVP!O!P(pQ(sP!O!P(vQ({OxQ~)QW!e~OY)jZ!P)j!P!Q+^!Q#O)j#O#P*[#P;'S)j;'S;=`+W<%lO)j~)mWOY)jZ!P)j!P!Q*V!Q#O)j#O#P*[#P;'S)j;'S;=`+W<%lO)j~*[Ol~~*_RO;'S)j;'S;=`*h;=`O)j~*kXOY)jZ!P)j!P!Q*V!Q#O)j#O#P*[#P;'S)j;'S;=`+W;=`<%l)j<%lO)j~+ZP;=`<%l)j~+cO!n~~+hQh~!O!P+n!Q![+c~+qP!Q![+t~+yPi~!Q![+t~,RO!U~~,WOt~~,]Pn~!_!`,`~,eOo~~,jQWP!_!`,p!`!a,u~,uO!i~Q,zO!WQ~-PPp~!_!`-S~-XOq~~-^SU~!Q![-X!c!}-X#R#S-X#T#o-X~-oOw~~-tOz~~-{S!]~U~!Q![-X!c!}-X#R#S-X#T#o-X~.^UU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y.p#Y#o-X~.uUU~!Q![-X!c!}-X#R#S-X#T#Y-X#Y#Z/X#Z#o-X~/^TU~!Q![-X!c!}-X#R#S-X#T#U/m#U#o-X~/rUU~!Q![-X!c!}-X#R#S-X#T#i-X#i#j0U#j#o-X~0ZUU~!Q![-X!c!}-X#R#S-X#T#`-X#`#a0m#a#o-X~0rUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i1U#i#o-X~1]S!o~U~!Q![-X!c!}-X#R#S-X#T#o-X~1nTU~!Q![-X!c!}-X#R#S-X#T#U1}#U#o-X~2SUU~!Q![-X!c!}-X#R#S-X#T#`-X#`#a2f#a#o-X~2kUU~!Q![-X!c!}-X#R#S-X#T#g-X#g#h2}#h#o-X~3SUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y3f#Y#o-X~3mSk~U~!Q![-X!c!}-X#R#S-X#T#o-X~4OVU~!Q![-X!c!}-X#R#S-X#T#a-X#a#b4e#b#c6x#c#o-X~4jUU~!Q![-X!c!}-X#R#S-X#T#d-X#d#e4|#e#o-X~5RUU~!Q![-X!c!}-X#R#S-X#T#c-X#c#d5e#d#o-X~5jUU~!Q![-X!c!}-X#R#S-X#T#f-X#f#g5|#g#o-X~6RUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i6e#i#o-X~6lS!_~U~!Q![-X!c!}-X#R#S-X#T#o-X~7PS!P~U~!Q![-X!c!}-X#R#S-X#T#o-X~7bUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y7t#Y#o-X~7yUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i8]#i#o-X~8dS}~U~!Q![-X!c!}-X#R#S-X#T#o-X~8uTU~!Q![-X!c!}-X#R#S-X#T#U9U#U#o-X~9ZUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i9m#i#o-X~9rUU~!Q![-X!c!}-X#R#S-X#T#V-X#V#W:U#W#o-X~:ZUU~!Q![-X!c!}-X#R#S-X#T#[-X#[#]:m#]#o-X~:tS!Y~U~!Q![-X!c!}-X#R#S-X#T#o-X~;VUU~!Q![-X!c!}-X#R#S-X#T#f-X#f#g;i#g#o-X~;nUU~!Q![-X!c!}-X#R#S-X#T#i-X#i#j<Q#j#o-X~<VUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y<i#Y#o-X~<pSj~U~!Q![-X!c!}-X#R#S-X#T#o-X~=ROs~~=UP#p#q=X~=^O!l~~=cOu~",
|
||||||
tokenizers: [0, 1],
|
tokenizers: [0, 1],
|
||||||
topRules: {"Source":[0,2]},
|
topRules: {"Source":[0,2]},
|
||||||
tokenPrec: 2481
|
tokenPrec: 2497
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,15 +2,15 @@
|
|||||||
import {LRParser} from "@lezer/lr"
|
import {LRParser} from "@lezer/lr"
|
||||||
export const parser = LRParser.deserialize({
|
export const parser = LRParser.deserialize({
|
||||||
version: 14,
|
version: 14,
|
||||||
states: "7vQYQPOOO#nQPO'#CaOOQO'#Cr'#CrO$wQPO'#CyO&UQPO'#DOO&^QPO'#DSO&eQPO'#DWO&mQPO'#CqO$wQPO'#DcO&wQPO'#DhOOQO'#Cq'#CqOOQO'#Cp'#CpO&|QPO'#CoO$wQPO'#CoOOQO'#Cn'#CnO)fQPO'#CmO.XQPO'#ClO0]QPO'#CkOOQO'#Cj'#CjO2TQPO'#CiO3xQPO'#ChO5jQPO'#CgO7UQPO'#CfOOQO'#Ce'#CeO7`QPO'#C`O7eQPO'#C_OOQO'#Dz'#DzQYQPOOO8xQPO'#D{O8}QPO,58{OOQO,59e,59eO9VQPO'#CaOOQO,59j,59jO9_QPO,59jOOQO,59n,59nO9gQPO,59nO9oQPO'#EOO9tQPO'#DYO9|QPO,59rO:RQPO'#CqO:`QPO'#D^O:hQQO,59vO:mQPO,59vO:rQPO,59]O:wQPO,59}OOQO,5:S,5:SO:|QPO'#DjOOQO,59[,59[O;TQPO,59[OOQO,59Z,59ZO$wQPO,59YO$wQPO,59XO$wQPO,59WOOQO'#Dr'#DrO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zOOQO,58y,58yOOQO-E7x-E7xOOQO,5:g,5:gOOQO-E7y-E7yO;YQPO1G/UO;bQPO1G/UOOQO1G/U1G/UO;jQPO1G/YO;qQPO1G/YOOQO1G/Y1G/YOOQO,5:j,5:jOOQO-E7|-E7|O$wQPO1G/^O$wQPO,59yO;yQPO,59xO<RQPO,59xO$wQPO1G/bO<ZQQO1G/bOOQO1G.w1G.wO<`QPO1G/iO<jQPO'#DkOOQO,5:U,5:UO<rQPO,5:UOOQO1G.v1G.vOOQO1G.t1G.tO<wQPO1G.sO@_QPO1G.rOAyQPO1G.qOOQO1G.p1G.pOCqQPO1G.oOEfQPO1G.nOFxQPO1G.mOOQO1G.l1G.lOOQO1G.f1G.fOOQO1G.s1G.sOOQO1G.r1G.rOOQO1G.q1G.qOOQO1G.o1G.oOOQO1G.n1G.nOOQO1G.m1G.mOOQO,5:h,5:hOOQO7+$p7+$pOHfQPO7+$pOOQO-E7z-E7zOOQO,5:i,5:iOOQO7+$t7+$tOHnQPO7+$tOOQO-E7{-E7{OOQO7+$x7+$xOOQO1G/e1G/eOHuQPO'#D_OOQO,5:k,5:kOHzQPO1G/dOOQO-E7}-E7}OOQO7+$|7+$|O$wQPO7+$|OOQO'#Df'#DfOISQPO'#DeOOQO7+%T7+%TOIXQPO7+%TOIaQPO,5:VOIhQPO,5:VOOQO1G/p1G/pOOQO<<H[<<H[PIpQPO'#D|OOQO<<H`<<H`P$wQPO'#D}PIuQPO'#EPOOQO<<Hh<<HhO$wQPO,5:POIzQPO<<HoOJUQPO<<HoOOQO<<Ho<<HoOJ^QPO1G/qOOQO1G/k1G/kOOQO,5:l,5:lOOQOAN>ZAN>ZOJeQPOAN>ZOOQO-E8O-E8OOOQOG23uG23uP<cQPO'#EQO$wQPO,59XO$wQPO,59WO$wQPO,59VO$wQPO,59TO$wQPO,59SO$wQPO,59ROJoQPO1G.rOKVQPO'#ClOKjQPO'#CkOL^QPO'#ChOM^QPO'#CgONaQPO'#CfO$wQPO,59WO$wQPO,59UO$wQPO,59QO! jQPO1G.qO!!QQPO'#CkO!#_QPO'#CiO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zO!$[QPO1G.oO!$rQPO1G.nO!%YQPO1G.mO!%zQPO'#CiO!&rQPO'#ChO!'gQPO'#CgO!(XQPO'#CfO!(vQPO'#C`",
|
states: "8fQYQPOOO#nQPO'#CaOOQO'#Cr'#CrO$wQPO'#CyO&UQPO'#DOO&^QQO'#DXO&hQPO'#DYO&pQPO'#CqO$wQPO'#DeO&zQPO'#DjOOQO'#Cq'#CqOOQO'#Cp'#CpO'PQPO'#CoO$wQPO'#CoOOQO'#Cn'#CnO)iQPO'#CmO.[QPO'#ClO0`QPO'#CkOOQO'#Cj'#CjO2WQPO'#CiO3{QPO'#ChO5mQPO'#CgO7XQPO'#CfOOQO'#Ce'#CeO7cQPO'#C`O7hQPO'#C_OOQO'#D|'#D|QYQPOOO8{QPO'#D}O9QQPO,58{OOQO,59e,59eO9YQPO'#CaOOQO,59j,59jO9bQPO,59jO$wQPO,59nOOQO,59s,59sO9jQPO,59sO9rQPO'#EQO9wQPO'#D[O:PQPO,59tO:UQPO'#CqO:cQPO'#D`O:kQQO,59xO:pQPO,59xO:uQPO,59]O:zQPO,5:POOQO,5:U,5:UO;PQPO'#DlOOQO,59[,59[O;WQPO,59[OOQO,59Z,59ZO$wQPO,59YO$wQPO,59XO$wQPO,59WOOQO'#Dt'#DtO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zOOQO,58y,58yOOQO-E7z-E7zOOQO,5:i,5:iOOQO-E7{-E7{O;]QPO1G/UO;eQPO1G/UOOQO1G/U1G/UO;mQPO1G/YO;uQPO1G/_O;|QPO1G/_OOQO1G/_1G/_OOQO,5:l,5:lOOQO-E8O-E8OO$wQPO1G/`O$wQPO,59{O<UQPO,59zO<^QPO,59zO$wQPO1G/dO<fQQO1G/dOOQO1G.w1G.wO<kQPO1G/kO<uQPO'#DmOOQO,5:W,5:WO<}QPO,5:WOOQO1G.v1G.vOOQO1G.t1G.tO=SQPO1G.sO@jQPO1G.rOBUQPO1G.qOOQO1G.p1G.pOC|QPO1G.oOEqQPO1G.nOGTQPO1G.mOOQO1G.l1G.lOOQO1G.f1G.fOOQO1G.s1G.sOOQO1G.r1G.rOOQO1G.q1G.qOOQO1G.o1G.oOOQO1G.n1G.nOOQO1G.m1G.mOOQO,5:j,5:jOOQO7+$p7+$pOHqQPO7+$pOOQO-E7|-E7|OOQO7+$t7+$tOHyQPO7+$tOOQO,5:k,5:kOOQO7+$y7+$yOIOQPO7+$yOOQO-E7}-E7}OOQO7+$z7+$zOOQO1G/g1G/gOIVQPO'#DaOOQO,5:m,5:mOI[QPO1G/fOOQO-E8P-E8POOQO7+%O7+%OO$wQPO7+%OOOQO'#Dh'#DhOIdQPO'#DgOOQO7+%V7+%VOIiQPO7+%VOIqQPO,5:XOIxQPO,5:XOOQO1G/r1G/rOOQO<<H[<<H[PJQQPO'#EOOOQO<<H`<<H`OOQO<<He<<HeP$wQPO'#EPPJVQPO'#EROOQO<<Hj<<HjO$wQPO,5:ROJ[QPO<<HqOJfQPO<<HqOOQO<<Hq<<HqOJnQPO1G/sOOQO1G/m1G/mOOQO,5:n,5:nOOQOAN>]AN>]OJuQPOAN>]OOQO-E8Q-E8QOOQOG23wG23wP<nQPO'#ESO$wQPO,59XO$wQPO,59WO$wQPO,59VO$wQPO,59TO$wQPO,59SO$wQPO,59ROKPQPO1G.rOKgQPO'#ClOKzQPO'#CkOLnQPO'#ChOMnQPO'#CgONqQPO'#CfO$wQPO,59WO$wQPO,59UO$wQPO,59QO! zQPO1G.qO!!bQPO'#CkO!#oQPO'#CiO$wQPO,59VO$wQPO,59UO$wQPO,59TO$wQPO,59SO$wQPO,59RO$wQPO,59QO$wQPO,58zO!$lQPO1G.oO!%SQPO1G.nO!%jQPO1G.mO!&[QPO'#CiO!'SQPO'#ChO!'wQPO'#CgO!(iQPO'#CfO!)WQPO'#C`",
|
||||||
stateData: "!)Y~O!wOSPOS~OUPOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OneXoeXpeXqeX!PeX!aeX!beX!ceX!deX!eeX!geX!heX!ieX!jeX!keX!leX!meX~OVlOUeXWTXgeXheXieXjeXkeXleXseXteXweX{eX!WeX!]eX!`eX!ueX~P!gOUYOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO{UO!PVO!WWO!]XO!`]O!a]O~OUoOupO~OyrO~P$wOUoO}|P~OUwO!TyO~P]Og}O~OV!QO!P!OOUcXgcXhcXicXjcXkcXlcXncXocXpcXqcXscXtcXwcX{cX!WcX!]cX!`cX!acX!bcX!ccX!dcX!ecX!gcX!hcX!icX!jcX!kcX!lcX!mcX!ucXxcXycX!TcXucX!ScX~O!b!SO!c!SOUaXgaXhaXiaXjaXkaXlaXnaXoaXpaXqaXsaXtaXwaX{aX!PaX!WaX!]aX!`aX!aaX!daX!eaX!gaX!haX!iaX!jaX!kaX!laX!maX!uaXVaXxaXyaX!TaXuaX!SaX~OU`Xg`Xh`Xi`Xj`Xk`Xl`Xn`Xo`Xp`Xq`Xs`Xt`Xw`X{`X!P`X!W`X!]`X!``X!e`X!g`X!h`X!i`X!j`X!k`X!l`X!m`X!u`Xx`Xy`X!T`Xu`X!S`X~O!a!TO!d!TO~P,OOn!VOo!VOp!VOq!VO!g!VO!h!VOU_Xg_Xh_Xi_Xj_Xk_Xl_Xs_Xt_Xw_X{_X!P_X!W_X!]_X!`_X!a_X!i_X!j_X!k_X!l_X!m_X!u_X~O!e!UO~P.cOU]Xg]Xh]Xi]Xj]Xk]Xl]Xn]Xo]Xp]Xq]Xs]Xt]Xw]X{]X!P]X!W]X!]]X!`]X!a]X!j]X!k]X!l]X!m]X!u]X~O!i!XO~P0dOU[Xg[Xh[Xi[Xj[Xk[Xl[Xn[Xo[Xp[Xq[Xs[Xt[Xw[X{[X!P[X!W[X!][X!`[X!a[X!k[X!l[X!m[X!u[X~O!j!YO~P2[OUZXgZXhZXiZXjZXkZXlZXnZXoZXpZXqZXsZXtZXwZX{ZX!PZX!WZX!]ZX!`ZX!aZX!lZX!mZX!uZX~O!k!ZO~P4POUYXgYXhYXiYXjYXkYXlYXnYXoYXpYXqYXsYXtYXwYX{YX!PYX!WYX!]YX!`YX!aYX!uYX~O!l![O!m!]O~P5qOW!^O~Ot!_OURXgRXhRXiRXjRXkRXlRXnRXoRXpRXqRXsRXwRX{RX!PRX!WRX!]RX!`RX!aRX!uRX~OU!aO~OVlOWTa~OVlOWTX~Ot!cOu!eO~Ox!fOy!hO~Ot!iO~OUoO}|X~O}!kO~O!S!lOVeX!TeX~P!gOx!mO!T!QX~O!U!oO~O!T!pO~O!T!qO~Os!rO~O!T!tO~P$wOU!vO~OUoOu#YO~Ot#ZOu#YO~Oy#^O~P$wOx#_Oy#^O~OU#cO!T!Qa~Ox#eO!T!Qa~O!U#hO~Ou#kO!Z#iO~P$wOx#mO!T!_X~O!T#oO~O!b!SO!c!SOUaigaihaiiaijaikailainaioaipaiqaisaitaiwai{ai!Pai!Wai!]ai!`ai!aai!dai!eai!gai!hai!iai!jai!kai!lai!mai!uaixaiyai!Taiuai!Sai~O!d!TOn`io`ip`iq`is`it`i!e`i!g`i!h`i!i`i!j`i!k`i!l`i!m`i~OU`ig`ih`ii`ij`ik`il`iw`i{`i!P`i!W`i!]`i!``i!a`i!u`i~P?^Os_it_i!i_i!j_i!k_i!l_i!m_i~O!e!UOU_ig_ih_ii_ij_ik_il_in_io_ip_iq_iw_i{_i!P_i!W_i!]_i!`_i!a_i!u_i~PAbOs]it]i!j]i!k]i!l]i!m]i~O!i!XOU]ig]ih]ii]ij]ik]il]in]io]ip]iq]iw]i{]i!P]i!W]i!]]i!`]i!a]i!u]i~PC]Os[it[i!k[i!l[i!m[i~O!j!YOU[ig[ih[ii[ij[ik[il[in[io[ip[iq[iw[i{[i!P[i!W[i!][i!`[i!a[i!u[i~PETO!k!ZOUZigZihZiiZijZikZilZinZioZipZiqZisZitZiwZi{Zi!PZi!WZi!]Zi!`Zi!aZi!lZi!mZi!uZi~OUoOu#pO~Oy#rO~P$wO!S!lO~OU#cO!T!Qi~O!S#vO~Ot#wOu#yO~O!T!_a~P$wOx#zO!T!_a~OUoO~OU#cO~Ou#}O!Z#iO~P$wOt$OOu#}O~O!T!_i~P$wOu$QO!Z#iO~P$wO!a!TOx`iy`i!T`iu`i!S`i~P?^O!a$SO!d$SOV`X!b`X!c`X~P,OO!e$TOV_X!b_X!c_X!d_Xx_Xy_X!T_Xu_X!S_X~P.cO!j$VOV[X!b[X!c[X!d[X!e[X!g[X!h[X!i[Xx[Xy[X!T[Xu[X!S[X~P2[O!k$WOVZX!bZX!cZX!dZX!eZX!gZX!hZX!iZX!jZXxZXyZX!TZXuZX!SZX~P4PO!l$XO!m$bOVYX!bYX!cYX!dYX!eYX!gYX!hYX!iYX!jYX!kYXxYXyYX!TYXuYX!SYX~P5qO!e$`Ox_iy_i!T_iu_i!S_i~PAbOn!VOo!VOp!VOq!VO!e$`O!g!VO!h!VOx_Xy_X!i_X!j_X!k_X!l_X!m_X!T_Xs_Xt_Xu_X!S_X~O!i$aOV]X!b]X!c]X!d]X!e]X!g]X!h]Xx]Xy]X!T]Xu]X!S]X~P0dO!i$gOx]iy]i!T]iu]i!S]i~PC]O!j$hOx[iy[i!T[iu[i!S[i~PETO!k$iOxZiyZi!lZi!mZi!TZisZitZiuZi!SZi~O!i$gOx]Xy]X!j]X!k]X!l]X!m]X!T]Xs]Xt]Xu]X!S]X~O!j$hOx[Xy[X!k[X!l[X!m[X!T[Xs[Xt[Xu[X!S[X~O!k$iOxZXyZX!lZX!mZX!TZXsZXtZXuZX!SZX~O!l$jO!m$kOxYXyYX!TYXsYXtYXuYX!SYX~OW$lO~O{}!W!]!mjkih!ZUj~",
|
stateData: "!)j~O!yOSPOS~OUPOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO}UO!RVO!YWO!_XO!b]O!c]O~OneXoeXpeXqeX!ReX!ceX!deX!eeX!feX!geX!ieX!jeX!keX!leX!meX!neX!oeX~OVlOUeXWTXgeXheXieXjeXkeXleXseXteXweX}eX!YeX!_eX!beX!weX~P!gOUYOgQOhQOiQOjQOkQOlQOnROoROpROqROsSOwTO}UO!RVO!YWO!_XO!b]O!c]O~OUoOupO~OxrOzsO~P$wOUoO!P!OP~OUxO!VzO~P]Og!OO~OV!RO!R!POUcXgcXhcXicXjcXkcXlcXncXocXpcXqcXscXtcXwcX}cX!YcX!_cX!bcX!ccX!dcX!ecX!fcX!gcX!icX!jcX!kcX!lcX!mcX!ncX!ocX!wcXycXzcX!VcXucX!UcX~O!d!TO!e!TOUaXgaXhaXiaXjaXkaXlaXnaXoaXpaXqaXsaXtaXwaX}aX!RaX!YaX!_aX!baX!caX!faX!gaX!iaX!jaX!kaX!laX!maX!naX!oaX!waXVaXyaXzaX!VaXuaX!UaX~OU`Xg`Xh`Xi`Xj`Xk`Xl`Xn`Xo`Xp`Xq`Xs`Xt`Xw`X}`X!R`X!Y`X!_`X!b`X!g`X!i`X!j`X!k`X!l`X!m`X!n`X!o`X!w`Xy`Xz`X!V`Xu`X!U`X~O!c!UO!f!UO~P,ROn!WOo!WOp!WOq!WO!i!WO!j!WOU_Xg_Xh_Xi_Xj_Xk_Xl_Xs_Xt_Xw_X}_X!R_X!Y_X!__X!b_X!c_X!k_X!l_X!m_X!n_X!o_X!w_X~O!g!VO~P.fOU]Xg]Xh]Xi]Xj]Xk]Xl]Xn]Xo]Xp]Xq]Xs]Xt]Xw]X}]X!R]X!Y]X!_]X!b]X!c]X!l]X!m]X!n]X!o]X!w]X~O!k!YO~P0gOU[Xg[Xh[Xi[Xj[Xk[Xl[Xn[Xo[Xp[Xq[Xs[Xt[Xw[X}[X!R[X!Y[X!_[X!b[X!c[X!m[X!n[X!o[X!w[X~O!l!ZO~P2_OUZXgZXhZXiZXjZXkZXlZXnZXoZXpZXqZXsZXtZXwZX}ZX!RZX!YZX!_ZX!bZX!cZX!nZX!oZX!wZX~O!m![O~P4SOUYXgYXhYXiYXjYXkYXlYXnYXoYXpYXqYXsYXtYXwYX}YX!RYX!YYX!_YX!bYX!cYX!wYX~O!n!]O!o!^O~P5tOW!_O~Ot!`OURXgRXhRXiRXjRXkRXlRXnRXoRXpRXqRXsRXwRX}RX!RRX!YRX!_RX!bRX!cRX!wRX~OU!bO~OVlOWTa~OVlOWTX~Ot!dOu!fO~Oy!hOz!jO~Ot!kO~OUoO!P!OX~O!P!mO~O!U!nOVeX!VeX~P!gOy!oO!V!SX~O!W!qO~O!V!rO~O!V!sO~Os!tO~O!V!vO~P$wOU!xO~OUoOu#[O~Ot#]Ou#[O~Oy#`Oz#_O~Oz#bO~P$wOy#cOz#bO~OU#gO!V!Sa~Oy#iO!V!Sa~O!W#lO~Ou#oO!]#mO~P$wOy#qO!V!aX~O!V#sO~O!d!TO!e!TOUaigaihaiiaijaikailainaioaipaiqaisaitaiwai}ai!Rai!Yai!_ai!bai!cai!fai!gai!iai!jai!kai!lai!mai!nai!oai!waiyaizai!Vaiuai!Uai~O!f!UOn`io`ip`iq`is`it`i!g`i!i`i!j`i!k`i!l`i!m`i!n`i!o`i~OU`ig`ih`ii`ij`ik`il`iw`i}`i!R`i!Y`i!_`i!b`i!c`i!w`i~P?iOs_it_i!k_i!l_i!m_i!n_i!o_i~O!g!VOU_ig_ih_ii_ij_ik_il_in_io_ip_iq_iw_i}_i!R_i!Y_i!__i!b_i!c_i!w_i~PAmOs]it]i!l]i!m]i!n]i!o]i~O!k!YOU]ig]ih]ii]ij]ik]il]in]io]ip]iq]iw]i}]i!R]i!Y]i!_]i!b]i!c]i!w]i~PChOs[it[i!m[i!n[i!o[i~O!l!ZOU[ig[ih[ii[ij[ik[il[in[io[ip[iq[iw[i}[i!R[i!Y[i!_[i!b[i!c[i!w[i~PE`O!m![OUZigZihZiiZijZikZilZinZioZipZiqZisZitZiwZi}Zi!RZi!YZi!_Zi!bZi!cZi!nZi!oZi!wZi~OUoOu#tO~Oz#vO~Oz#wO~P$wO!U!nO~OU#gO!V!Si~O!U#{O~Ot#|Ou$OO~O!V!aa~P$wOy$PO!V!aa~OUoO~OU#gO~Ou$SO!]#mO~P$wOt$TOu$SO~O!V!ai~P$wOu$VO!]#mO~P$wO!c!UOy`iz`i!V`iu`i!U`i~P?iO!c$XO!f$XOV`X!d`X!e`X~P,RO!g$YOV_X!d_X!e_X!f_Xy_Xz_X!V_Xu_X!U_X~P.fO!l$[OV[X!d[X!e[X!f[X!g[X!i[X!j[X!k[Xy[Xz[X!V[Xu[X!U[X~P2_O!m$]OVZX!dZX!eZX!fZX!gZX!iZX!jZX!kZX!lZXyZXzZX!VZXuZX!UZX~P4SO!n$^O!o$gOVYX!dYX!eYX!fYX!gYX!iYX!jYX!kYX!lYX!mYXyYXzYX!VYXuYX!UYX~P5tO!g$eOy_iz_i!V_iu_i!U_i~PAmOn!WOo!WOp!WOq!WO!g$eO!i!WO!j!WOy_Xz_X!k_X!l_X!m_X!n_X!o_X!V_Xs_Xt_Xu_X!U_X~O!k$fOV]X!d]X!e]X!f]X!g]X!i]X!j]Xy]Xz]X!V]Xu]X!U]X~P0gO!k$lOy]iz]i!V]iu]i!U]i~PChO!l$mOy[iz[i!V[iu[i!U[i~PE`O!m$nOyZizZi!nZi!oZi!VZisZitZiuZi!UZi~O!k$lOy]Xz]X!l]X!m]X!n]X!o]X!V]Xs]Xt]Xu]X!U]X~O!l$mOy[Xz[X!m[X!n[X!o[X!V[Xs[Xt[Xu[X!U[X~O!m$nOyZXzZX!nZX!oZX!VZXsZXtZXuZX!UZX~O!n$oO!o$pOyYXzYX!VYXsYXtYXuYX!UYX~OW$qO~O}!P!Y!_!ojkih!]Uj~",
|
||||||
goto: "3l!uPPP!v!z#[PPP#h$m%]%}&x'v(w)s*z,S-Y.b/f0jPPPPPP0jPPPP0jPPP0jPPP0jP1nP0jP1q1tPPP0jP1|2UP0jP2[2_PPPPPP2bPPPPPPP2k2q2x3O3Y3`3fTjOkSiOkQqSStUuV#X!c#Z#qShOk]$tSUu!c#Z#qSiOkQnRQsTQ{VQ|WQ!s!OS#Q!^$lY#]!f#_#m#s#zQ#a!kQ#b!lQ#g!oW#i!r#w$O$RQ#u#hR#{#v!OgORTVWk!O!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$lV#P!]$b$kWfOk!]!^Y$_R!k!o#h$bs$sTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lWeOk!]!^Q#O![Q#W$XY$^R!k!o#h$bQ$o$js$rTVW!O!f!l!r#_#m#s#v#w#z$O$R$k$lYdOk![!]!^Q!}!ZQ#V$W[$]R!k!o#h$X$bQ$n$iu$qTVW!O!f!l!r#_#m#s#v#w#z$O$R$j$k$l[cOk!Z![!]!^Q!|!YQ#U$V^$eR!k!o#h$W$X$bQ$m$hw$pTVW!O!f!l!r#_#m#s#v#w#z$O$R$i$j$k$l!hbORTVWk!O!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$V$W$X$b$h$i$j$k$lV!{!X$a$g`aOk!X!Y!Z![!]!^Q!z!WQ#T$Ub$[R!k!o#h$V$W$X$a$bQ$c$f{$dTVW!O!f!l!r#_#m#s#v#w#z$O$R$g$h$i$j$k$l!``OTVWk!O!W!X!Y!Z![!]!^!f!l!r#_#m#s#v#w#z$O$R$f$g$h$i$j$k$lQ!y!UQ#S$TQ$Y$`e$ZR!k!o#h$U$V$W$X$a$b!z_ORTVWk!O!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!x!TR#R$S#O^ORTVWk!O!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lQ!R]R!w!S#T[ORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TZORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$l#TYORTVW]k!O!S!T!U!W!X!Y!Z![!]!^!f!k!l!o!r#_#h#m#s#v#w#z$O$R$S$T$U$V$W$X$`$a$b$f$g$h$i$j$k$lRvURzVQxVV#d!m#e#tQ#l!rV#|#w$O$RX#j!r#w$O$RR!P[R!u!OQ!WaQ$U$[R$f$dQkOR!`kSmPoR!bmQ!dqR#[!dQ!gsS#`!g#nR#n!sQuUR!juQ!nxR#f!nQ#x#lR$P#x",
|
goto: "4O!wPPP!x!|#^PPP#j$r%c&U'Q(P)R*O+W,a-h.q/v0{PPPPPP0{PPPP0{PPP0{PPPP0{0{P2QP0{P2T2WPPP0{P2`2hP0{P2n2qPPPPPP2tPPPPPPP2}3T3[3b3l3r3xTjOkSiOkQqSSuUvV#Z!d#]#uShOk]$ySUv!d#]#uSiOkQnRQtTQ|VQ}WQ!grQ!u!PS#S!_$qY#a!h#c#q#x$PQ#e!mQ#f!nQ#k!qW#m!t#|$T$WQ#z#lR$Q#{!QgORTVWkr!P!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$qV#R!^$g$pWfOk!^!_Y$dR!m!q#l$gu$xTVWr!P!h!n!t#c#q#x#{#|$P$T$W$p$qWeOk!^!_Q#Q!]Q#Y$^Y$cR!m!q#l$gQ$t$ou$wTVWr!P!h!n!t#c#q#x#{#|$P$T$W$p$qYdOk!]!^!_Q#P![Q#X$][$bR!m!q#l$^$gQ$s$nw$vTVWr!P!h!n!t#c#q#x#{#|$P$T$W$o$p$q[cOk![!]!^!_Q#O!ZQ#W$[^$jR!m!q#l$]$^$gQ$r$my$uTVWr!P!h!n!t#c#q#x#{#|$P$T$W$n$o$p$q!jbORTVWkr!P!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$[$]$^$g$m$n$o$p$qV!}!Y$f$l`aOk!Y!Z![!]!^!_Q!|!XQ#V$Zb$aR!m!q#l$[$]$^$f$gQ$h$k}$iTVWr!P!h!n!t#c#q#x#{#|$P$T$W$l$m$n$o$p$q!b`OTVWkr!P!X!Y!Z![!]!^!_!h!n!t#c#q#x#{#|$P$T$W$k$l$m$n$o$p$qQ!{!VQ#U$YQ$_$ee$`R!m!q#l$Z$[$]$^$f$g!|_ORTVWkr!P!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qQ!z!UR#T$X#Q^ORTVWkr!P!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qQ!S]R!y!T#V[ORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$q#VZORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$q#VYORTVW]kr!P!T!U!V!X!Y!Z![!]!^!_!h!m!n!q!t#c#l#q#x#{#|$P$T$W$X$Y$Z$[$]$^$e$f$g$k$l$m$n$o$p$qRwUR{VQyVV#h!o#i#yQ#p!tV$R#|$T$WX#n!t#|$T$WR!Q[R!w!PQ!XaQ$Z$aR$k$iQkOR!akSmPoR!cmQ!eqR#^!eQ!itS#d!i#rR#r!uQvUR!lvQ!pyR#j!pQ#}#pR$U#}",
|
||||||
nodeNames: "⚠ Comment Source Statement FieldDefinition FieldPath Identifier Dot Equal Expression DefaultExpression PatchExpression ComposeExpression LogicalOrExpression LogicalAndExpression ComparisonExpression ConcatExpression AdditiveExpression MultiplicativeExpression UnaryExpression PostfixExpression PrimaryExpression Literal String Integer Float True False Regex ComparisonConstraint Lt Lte Gt Gte Object LBrace Semicolon RBrace Array LBracket Comma RBracket LetExpression Let FieldDefinitionList In FunctionExpression LParen ParameterList Parameter Colon RParen Arrow MatchExpression Match MatchArm Pattern Underscore ImportExpression Import CallSuffix ArgumentList Bang Minus Star Slash Plus PlusPlus CompareOperator EqualEqual BangEqual AmpAmp PipePipe Amp SlashSlash Default",
|
nodeNames: "⚠ Comment Source Statement FieldDefinition FieldPath Identifier Dot Equal Expression DefaultExpression PatchExpression ComposeExpression LogicalOrExpression LogicalAndExpression ComparisonExpression ConcatExpression AdditiveExpression MultiplicativeExpression UnaryExpression PostfixExpression PrimaryExpression Literal String Integer Float True False Regex ComparisonConstraint Lt Lte Gt Gte Object LBrace Semicolon RBrace ArrayConstraint LBracket Ellipsis Comma RBracket Array LetExpression Let FieldDefinitionList In FunctionExpression LParen ParameterList Parameter Colon RParen Arrow MatchExpression Match MatchArm Pattern Underscore ImportExpression Import CallSuffix ArgumentList Bang Minus Star Slash Plus PlusPlus CompareOperator EqualEqual BangEqual AmpAmp PipePipe Amp SlashSlash Default",
|
||||||
maxTerm: 85,
|
maxTerm: 87,
|
||||||
skippedNodes: [0,1],
|
skippedNodes: [0,1],
|
||||||
repeatNodeCount: 7,
|
repeatNodeCount: 7,
|
||||||
tokenData: "=T~R!PX^$Upq$Uqr$yrs%Wst&zvw'cxy'pyz'uz{'z{|(P|}(^}!O(c!O!P(h!P!Q(m!Q![+T![!]+n!]!^+s!^!_+x!_!`,V!`!a,l!c!},y!}#O-[#P#Q-a#R#S-f#T#W,y#W#X-y#X#Y,y#Y#Z1Z#Z#],y#]#^3k#^#`,y#`#a6}#a#b8b#b#h,y#h#i:r#i#o,y#o#p<n#p#q<s#q#r=O#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~$ZY!w~X^$Upq$U#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~%OP!`~!_!`%R~%WO!h~~%ZWOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t<%lO%W~%xOg~~%{RO;'S%W;'S;=`&U;=`O%W~&XXOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t;=`<%l%W<%lO%W~&wP;=`<%l%W~'PSP~OY&zZ;'S&z;'S;=`']<%lO&z~'`P;=`<%l&z~'hP!k~vw'k~'pO!i~~'uO!P~~'zO!T~~(PO!b~~(UP!d~{|(X~(^O!e~~(cOx~~(hO!a~~(mOV~~(rW!c~OY)[Z!P)[!P!Q+O!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)_WOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x<%lO)[~)|Ol~~*PRO;'S)[;'S;=`*Y;=`O)[~*]XOY)[Z!P)[!P!Q)w!Q#O)[#O#P)|#P;'S)[;'S;=`*x;=`<%l)[<%lO)[~*{P;=`<%l)[~+TO!l~~+YQh~!O!P+`!Q![+T~+cP!Q![+f~+kPi~!Q![+f~+sO!S~~+xOt~~+}Pn~!_!`,Q~,VOo~~,[QWP!_!`,b!`!a,g~,gO!g~Q,lO!UQ~,qPp~!_!`,t~,yOq~~-OSU~!Q![,y!c!},y#R#S,y#T#o,y~-aOw~~-fOy~~-mS!Z~U~!Q![,y!c!},y#R#S,y#T#o,y~.OUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y.b#Y#o,y~.gUU~!Q![,y!c!},y#R#S,y#T#Y,y#Y#Z.y#Z#o,y~/OTU~!Q![,y!c!},y#R#S,y#T#U/_#U#o,y~/dUU~!Q![,y!c!},y#R#S,y#T#i,y#i#j/v#j#o,y~/{UU~!Q![,y!c!},y#R#S,y#T#`,y#`#a0_#a#o,y~0dUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i0v#i#o,y~0}S!m~U~!Q![,y!c!},y#R#S,y#T#o,y~1`TU~!Q![,y!c!},y#R#S,y#T#U1o#U#o,y~1tUU~!Q![,y!c!},y#R#S,y#T#`,y#`#a2W#a#o,y~2]UU~!Q![,y!c!},y#R#S,y#T#g,y#g#h2o#h#o,y~2tUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y3W#Y#o,y~3_Sk~U~!Q![,y!c!},y#R#S,y#T#o,y~3pVU~!Q![,y!c!},y#R#S,y#T#a,y#a#b4V#b#c6j#c#o,y~4[UU~!Q![,y!c!},y#R#S,y#T#d,y#d#e4n#e#o,y~4sUU~!Q![,y!c!},y#R#S,y#T#c,y#c#d5V#d#o,y~5[UU~!Q![,y!c!},y#R#S,y#T#f,y#f#g5n#g#o,y~5sUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i6V#i#o,y~6^S!]~U~!Q![,y!c!},y#R#S,y#T#o,y~6qS}~U~!Q![,y!c!},y#R#S,y#T#o,y~7SUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y7f#Y#o,y~7kUU~!Q![,y!c!},y#R#S,y#T#h,y#h#i7}#i#o,y~8US{~U~!Q![,y!c!},y#R#S,y#T#o,y~8gTU~!Q![,y!c!},y#R#S,y#T#U8v#U#o,y~8{UU~!Q![,y!c!},y#R#S,y#T#h,y#h#i9_#i#o,y~9dUU~!Q![,y!c!},y#R#S,y#T#V,y#V#W9v#W#o,y~9{UU~!Q![,y!c!},y#R#S,y#T#[,y#[#]:_#]#o,y~:fS!W~U~!Q![,y!c!},y#R#S,y#T#o,y~:wUU~!Q![,y!c!},y#R#S,y#T#f,y#f#g;Z#g#o,y~;`UU~!Q![,y!c!},y#R#S,y#T#i,y#i#j;r#j#o,y~;wUU~!Q![,y!c!},y#R#S,y#T#X,y#X#Y<Z#Y#o,y~<bSj~U~!Q![,y!c!},y#R#S,y#T#o,y~<sOs~~<vP#p#q<y~=OO!j~~=TOu~",
|
tokenData: "=c~R!PX^$Upq$Uqr$yrs%Wst&zvw'cxy'pyz'uz{'z{|(P|}(^}!O(c!O!P(h!P!Q({!Q![+c![!]+|!]!^,R!^!_,W!_!`,e!`!a,z!c!}-X!}#O-j#P#Q-o#R#S-t#T#W-X#W#X.X#X#Y-X#Y#Z1i#Z#]-X#]#^3y#^#`-X#`#a7]#a#b8p#b#h-X#h#i;Q#i#o-X#o#p<|#p#q=R#q#r=^#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~$ZY!y~X^$Upq$U#y#z$U$f$g$U#BY#BZ$U$IS$I_$U$I|$JO$U$JT$JU$U$KV$KW$U&FU&FV$U~%OP!b~!_!`%R~%WO!j~~%ZWOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t<%lO%W~%xOg~~%{RO;'S%W;'S;=`&U;=`O%W~&XXOY%WZr%Wrs%ss#O%W#O#P%x#P;'S%W;'S;=`&t;=`<%l%W<%lO%W~&wP;=`<%l%W~'PSP~OY&zZ;'S&z;'S;=`']<%lO&z~'`P;=`<%l&z~'hP!m~vw'k~'pO!k~~'uO!R~~'zO!V~~(PO!d~~(UP!f~{|(X~(^O!g~~(cOy~~(hO!c~R(mPVP!O!P(pQ(sP!O!P(vQ({OxQ~)QW!e~OY)jZ!P)j!P!Q+^!Q#O)j#O#P*[#P;'S)j;'S;=`+W<%lO)j~)mWOY)jZ!P)j!P!Q*V!Q#O)j#O#P*[#P;'S)j;'S;=`+W<%lO)j~*[Ol~~*_RO;'S)j;'S;=`*h;=`O)j~*kXOY)jZ!P)j!P!Q*V!Q#O)j#O#P*[#P;'S)j;'S;=`+W;=`<%l)j<%lO)j~+ZP;=`<%l)j~+cO!n~~+hQh~!O!P+n!Q![+c~+qP!Q![+t~+yPi~!Q![+t~,RO!U~~,WOt~~,]Pn~!_!`,`~,eOo~~,jQWP!_!`,p!`!a,u~,uO!i~Q,zO!WQ~-PPp~!_!`-S~-XOq~~-^SU~!Q![-X!c!}-X#R#S-X#T#o-X~-oOw~~-tOz~~-{S!]~U~!Q![-X!c!}-X#R#S-X#T#o-X~.^UU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y.p#Y#o-X~.uUU~!Q![-X!c!}-X#R#S-X#T#Y-X#Y#Z/X#Z#o-X~/^TU~!Q![-X!c!}-X#R#S-X#T#U/m#U#o-X~/rUU~!Q![-X!c!}-X#R#S-X#T#i-X#i#j0U#j#o-X~0ZUU~!Q![-X!c!}-X#R#S-X#T#`-X#`#a0m#a#o-X~0rUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i1U#i#o-X~1]S!o~U~!Q![-X!c!}-X#R#S-X#T#o-X~1nTU~!Q![-X!c!}-X#R#S-X#T#U1}#U#o-X~2SUU~!Q![-X!c!}-X#R#S-X#T#`-X#`#a2f#a#o-X~2kUU~!Q![-X!c!}-X#R#S-X#T#g-X#g#h2}#h#o-X~3SUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y3f#Y#o-X~3mSk~U~!Q![-X!c!}-X#R#S-X#T#o-X~4OVU~!Q![-X!c!}-X#R#S-X#T#a-X#a#b4e#b#c6x#c#o-X~4jUU~!Q![-X!c!}-X#R#S-X#T#d-X#d#e4|#e#o-X~5RUU~!Q![-X!c!}-X#R#S-X#T#c-X#c#d5e#d#o-X~5jUU~!Q![-X!c!}-X#R#S-X#T#f-X#f#g5|#g#o-X~6RUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i6e#i#o-X~6lS!_~U~!Q![-X!c!}-X#R#S-X#T#o-X~7PS!P~U~!Q![-X!c!}-X#R#S-X#T#o-X~7bUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y7t#Y#o-X~7yUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i8]#i#o-X~8dS}~U~!Q![-X!c!}-X#R#S-X#T#o-X~8uTU~!Q![-X!c!}-X#R#S-X#T#U9U#U#o-X~9ZUU~!Q![-X!c!}-X#R#S-X#T#h-X#h#i9m#i#o-X~9rUU~!Q![-X!c!}-X#R#S-X#T#V-X#V#W:U#W#o-X~:ZUU~!Q![-X!c!}-X#R#S-X#T#[-X#[#]:m#]#o-X~:tS!Y~U~!Q![-X!c!}-X#R#S-X#T#o-X~;VUU~!Q![-X!c!}-X#R#S-X#T#f-X#f#g;i#g#o-X~;nUU~!Q![-X!c!}-X#R#S-X#T#i-X#i#j<Q#j#o-X~<VUU~!Q![-X!c!}-X#R#S-X#T#X-X#X#Y<i#Y#o-X~<pSj~U~!Q![-X!c!}-X#R#S-X#T#o-X~=ROs~~=UP#p#q=X~=^O!l~~=cOu~",
|
||||||
tokenizers: [0, 1],
|
tokenizers: [0, 1],
|
||||||
topRules: {"Source":[0,2]},
|
topRules: {"Source":[0,2]},
|
||||||
tokenPrec: 2481
|
tokenPrec: 2497
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -37,41 +37,43 @@ export const
|
|||||||
LBrace = 35,
|
LBrace = 35,
|
||||||
Semicolon = 36,
|
Semicolon = 36,
|
||||||
RBrace = 37,
|
RBrace = 37,
|
||||||
Array = 38,
|
ArrayConstraint = 38,
|
||||||
LBracket = 39,
|
LBracket = 39,
|
||||||
Comma = 40,
|
Ellipsis = 40,
|
||||||
RBracket = 41,
|
Comma = 41,
|
||||||
LetExpression = 42,
|
RBracket = 42,
|
||||||
Let = 43,
|
Array = 43,
|
||||||
FieldDefinitionList = 44,
|
LetExpression = 44,
|
||||||
In = 45,
|
Let = 45,
|
||||||
FunctionExpression = 46,
|
FieldDefinitionList = 46,
|
||||||
LParen = 47,
|
In = 47,
|
||||||
ParameterList = 48,
|
FunctionExpression = 48,
|
||||||
Parameter = 49,
|
LParen = 49,
|
||||||
Colon = 50,
|
ParameterList = 50,
|
||||||
RParen = 51,
|
Parameter = 51,
|
||||||
Arrow = 52,
|
Colon = 52,
|
||||||
MatchExpression = 53,
|
RParen = 53,
|
||||||
Match = 54,
|
Arrow = 54,
|
||||||
MatchArm = 55,
|
MatchExpression = 55,
|
||||||
Pattern = 56,
|
Match = 56,
|
||||||
Underscore = 57,
|
MatchArm = 57,
|
||||||
ImportExpression = 58,
|
Pattern = 58,
|
||||||
Import = 59,
|
Underscore = 59,
|
||||||
CallSuffix = 60,
|
ImportExpression = 60,
|
||||||
ArgumentList = 61,
|
Import = 61,
|
||||||
Bang = 62,
|
CallSuffix = 62,
|
||||||
Minus = 63,
|
ArgumentList = 63,
|
||||||
Star = 64,
|
Bang = 64,
|
||||||
Slash = 65,
|
Minus = 65,
|
||||||
Plus = 66,
|
Star = 66,
|
||||||
PlusPlus = 67,
|
Slash = 67,
|
||||||
CompareOperator = 68,
|
Plus = 68,
|
||||||
EqualEqual = 69,
|
PlusPlus = 69,
|
||||||
BangEqual = 70,
|
CompareOperator = 70,
|
||||||
AmpAmp = 71,
|
EqualEqual = 71,
|
||||||
PipePipe = 72,
|
BangEqual = 72,
|
||||||
Amp = 73,
|
AmpAmp = 73,
|
||||||
SlashSlash = 74,
|
PipePipe = 74,
|
||||||
Default = 75
|
Amp = 75,
|
||||||
|
SlashSlash = 76,
|
||||||
|
Default = 77
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const parserWithMetadata = parser.configure({
|
|||||||
Regex: t.regexp,
|
Regex: t.regexp,
|
||||||
'Integer Float': t.number,
|
'Integer Float': t.number,
|
||||||
Comment: t.lineComment,
|
Comment: t.lineComment,
|
||||||
'Plus Minus Star Slash PlusPlus Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
|
'Plus Minus Star Slash PlusPlus Ellipsis Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
|
||||||
'LBrace RBrace': t.brace,
|
'LBrace RBrace': t.brace,
|
||||||
'LBracket RBracket': t.squareBracket,
|
'LBracket RBracket': t.squareBracket,
|
||||||
'LParen RParen': t.paren,
|
'LParen RParen': t.paren,
|
||||||
@@ -21,12 +21,14 @@ const parserWithMetadata = parser.configure({
|
|||||||
indentNodeProp.add({
|
indentNodeProp.add({
|
||||||
Object: context => context.column(context.node.from) + context.unit,
|
Object: context => context.column(context.node.from) + context.unit,
|
||||||
Array: context => context.column(context.node.from) + context.unit,
|
Array: context => context.column(context.node.from) + context.unit,
|
||||||
|
ArrayConstraint: context => context.column(context.node.from) + context.unit,
|
||||||
MatchExpression: context => context.column(context.node.from) + context.unit,
|
MatchExpression: context => context.column(context.node.from) + context.unit,
|
||||||
LetExpression: context => context.column(context.node.from) + context.unit,
|
LetExpression: context => context.column(context.node.from) + context.unit,
|
||||||
}),
|
}),
|
||||||
foldNodeProp.add({
|
foldNodeProp.add({
|
||||||
Object: foldDelimited('{', '}'),
|
Object: foldDelimited('{', '}'),
|
||||||
Array: foldDelimited('[', ']'),
|
Array: foldDelimited('[', ']'),
|
||||||
|
ArrayConstraint: foldDelimited('[', ']'),
|
||||||
MatchExpression: foldDelimited('{', '}'),
|
MatchExpression: foldDelimited('{', '}'),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const parserWithMetadata = parser.configure({
|
|||||||
Regex: t.regexp,
|
Regex: t.regexp,
|
||||||
'Integer Float': t.number,
|
'Integer Float': t.number,
|
||||||
Comment: t.lineComment,
|
Comment: t.lineComment,
|
||||||
'Plus Minus Star Slash PlusPlus Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
|
'Plus Minus Star Slash PlusPlus Ellipsis Equal EqualEqual Bang BangEqual Amp AmpAmp PipePipe SlashSlash Gt Gte Lt Lte Arrow': t.operator,
|
||||||
'LBrace RBrace': t.brace,
|
'LBrace RBrace': t.brace,
|
||||||
'LBracket RBracket': t.squareBracket,
|
'LBracket RBracket': t.squareBracket,
|
||||||
'LParen RParen': t.paren,
|
'LParen RParen': t.paren,
|
||||||
@@ -31,12 +31,14 @@ const parserWithMetadata = parser.configure({
|
|||||||
indentNodeProp.add({
|
indentNodeProp.add({
|
||||||
Object: context => context.column(context.node.from) + context.unit,
|
Object: context => context.column(context.node.from) + context.unit,
|
||||||
Array: context => context.column(context.node.from) + context.unit,
|
Array: context => context.column(context.node.from) + context.unit,
|
||||||
|
ArrayConstraint: context => context.column(context.node.from) + context.unit,
|
||||||
MatchExpression: context => context.column(context.node.from) + context.unit,
|
MatchExpression: context => context.column(context.node.from) + context.unit,
|
||||||
LetExpression: context => context.column(context.node.from) + context.unit,
|
LetExpression: context => context.column(context.node.from) + context.unit,
|
||||||
}),
|
}),
|
||||||
foldNodeProp.add({
|
foldNodeProp.add({
|
||||||
Object: foldDelimited('{', '}'),
|
Object: foldDelimited('{', '}'),
|
||||||
Array: foldDelimited('[', ']'),
|
Array: foldDelimited('[', ']'),
|
||||||
|
ArrayConstraint: foldDelimited('[', ']'),
|
||||||
MatchExpression: foldDelimited('{', '}'),
|
MatchExpression: foldDelimited('{', '}'),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -41,7 +41,7 @@ export function highlightDecodalTokens(source, tokens) {
|
|||||||
|
|
||||||
function tokenClass(kind, text) {
|
function tokenClass(kind, text) {
|
||||||
if (['let', 'in', 'fn', 'match', 'import', 'default'].includes(kind)) return 'tok-keyword';
|
if (['let', 'in', 'fn', 'match', 'import', 'default'].includes(kind)) return 'tok-keyword';
|
||||||
if (kind === 'ident' && ['String', 'Int', 'Float', 'Bool', 'Array'].includes(text)) return 'tok-type';
|
if (kind === 'ident' && ['String', 'Int', 'Float', 'Bool'].includes(text)) return 'tok-type';
|
||||||
if (kind === 'ident') return '';
|
if (kind === 'ident') return '';
|
||||||
if (['true', 'false'].includes(kind)) return 'tok-literal';
|
if (['true', 'false'].includes(kind)) return 'tok-literal';
|
||||||
if (['int', 'float'].includes(kind)) return 'tok-number';
|
if (['int', 'float'].includes(kind)) return 'tok-number';
|
||||||
@@ -60,6 +60,7 @@ function tokenClass(kind, text) {
|
|||||||
'pipe_pipe',
|
'pipe_pipe',
|
||||||
'plus',
|
'plus',
|
||||||
'plus_plus',
|
'plus_plus',
|
||||||
|
'ellipsis',
|
||||||
'minus',
|
'minus',
|
||||||
'star',
|
'star',
|
||||||
'slash',
|
'slash',
|
||||||
@@ -255,6 +256,7 @@ function isOperatorStart(char) {
|
|||||||
|
|
||||||
function readOperator(source, start) {
|
function readOperator(source, start) {
|
||||||
let index = start + 1;
|
let index = start + 1;
|
||||||
|
if (source.startsWith('...', start)) return start + 3;
|
||||||
if ('&|/+'.includes(source[start]) && source[index] === source[start]) return index + 1;
|
if ('&|/+'.includes(source[start]) && source[index] === source[start]) return index + 1;
|
||||||
if ((source[start] === '<' || source[start] === '>' || source[start] === '=' || source[start] === '!') && source[index] === '=') {
|
if ((source[start] === '<' || source[start] === '>' || source[start] === '=' || source[start] === '!') && source[index] === '=') {
|
||||||
index += 1;
|
index += 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user