@neocompose/cli 0.33.2 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.34.1] - 2026-08-19
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Accept the advertised positional `NeoLookupVariantFolder<TObject, TValue>`
|
|
8
|
+
constructor form and lower it identically to named `path`, `collection`, and
|
|
9
|
+
`collectionValue` arguments.
|
|
10
|
+
- Preserve lookup-variant member `TValue` through the CLI/server document
|
|
11
|
+
boundary under the canonical `valueTypeInfo` field, including an open generic
|
|
12
|
+
parameter authored by an enclosing class.
|
|
13
|
+
- Give `neo test` the candidate project's variants and variant folders, so
|
|
14
|
+
variants declared in the same pending push resolve alongside root values and
|
|
15
|
+
declared list indexes.
|
|
16
|
+
|
|
17
|
+
## [0.34.0] - 2026-08-19
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- P71 `List.Repeat`: call `List.Repeat(value, count)` from any NeoScript body
|
|
22
|
+
to build a list of `count` copies of `value`. The entry type is inferred
|
|
23
|
+
from the value and joined with the assignment context, so
|
|
24
|
+
`List<float> w = List.Repeat(0, 4)` widens; `count` must be an `int`, a
|
|
25
|
+
negative count is a runtime error, and materialization is charged to the
|
|
26
|
+
shared collection-entries budget.
|
|
27
|
+
- Unity export schema version 25, so an SDK that predates `listRepeat` refuses
|
|
28
|
+
the export with the standard upgrade message instead of failing
|
|
29
|
+
mid-deserialize.
|
|
30
|
+
|
|
3
31
|
## [0.33.2] - 2026-08-19
|
|
4
32
|
|
|
5
33
|
### Fixed
|
package/dist/neo.mjs
CHANGED
|
@@ -1336,7 +1336,7 @@ function vectorTypes() {
|
|
|
1336
1336
|
members: structuredLeafFieldProperties(name)
|
|
1337
1337
|
}));
|
|
1338
1338
|
}
|
|
1339
|
-
var NEO_PROJECT_IGNORED_DIRECTORY_NAMES, NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_ANNOTATION_TYPES, NEOSCRIPT_BUILTIN_NAMESPACES, NEOSCRIPT_BUILTIN_TYPES, NEO_VARIANT_TYPE_NAME, NEO_VARIANT_FOLDER_TYPE_NAME, NEO_LOOKUP_VARIANT_TYPE_NAME, NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME, NEO_VARIANT_SCOPE_NAME, NEO_VARIANT_RESERVED_NAME, NEO_VARIANT_FOLDER_PATH_SEPARATOR, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_MATH_TYPE_ID, MATH_INFERENCE_RULE, MATH_INTEGRAL_RULE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
1339
|
+
var NEO_PROJECT_IGNORED_DIRECTORY_NAMES, NEOSCRIPT_KEYWORDS, NEOSCRIPT_INFERRED_LOCAL_KEYWORD, NEOSCRIPT_CONSTRUCTOR_KEYWORD, NEOSCRIPT_PRIMITIVE_TYPES, NEOSCRIPT_BUILTIN_ANNOTATION_TYPES, NEOSCRIPT_BUILTIN_NAMESPACES, NEOSCRIPT_BUILTIN_TYPES, NEO_VARIANT_TYPE_NAME, NEO_VARIANT_FOLDER_TYPE_NAME, NEO_LOOKUP_VARIANT_TYPE_NAME, NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME, NEO_VARIANT_SCOPE_NAME, NEO_VARIANT_RESERVED_NAME, NEO_VARIANT_FOLDER_PATH_SEPARATOR, NEOSCRIPT_OPERATORS, NEOSCRIPT_STATEMENT_SNIPPETS, STRING_TYPE, INT_TYPE, FLOAT_TYPE, BOOL_TYPE, IMAGE_REF_TYPE, SPRITE_INFO_TYPE, FLOAT_OPTIONAL_TYPE, NEOSCRIPT_STRUCTURED_LEAF_FIELDS, NEOSCRIPT_IMAGE_REGISTRY_TYPE, NEOSCRIPT_AUDIO_CLIP_REGISTRY_TYPE, NEOSCRIPT_PENDING_SYMBOL_ID_PREFIX, REGISTRY_ENTRY_TYPES, NEOSCRIPT_GLOBALS, NEOSCRIPT_SPRITE_INFO_EMPTY_MEMBER_ID, NEOSCRIPT_SPRITE_INFO_EMPTY_VALUE, NEOSCRIPT_MATH_TYPE_ID, MATH_INFERENCE_RULE, MATH_INTEGRAL_RULE, NEOSCRIPT_LIST_TYPE_NAME, NEOSCRIPT_LIST_TYPE_ID, NEOSCRIPT_LIST_REPEAT_NAME, LIST_ENTRY_TYPE, NEOSCRIPT_BUILTIN_TYPE_SYMBOLS;
|
|
1340
1340
|
var init_language_spec = __esm({
|
|
1341
1341
|
"../packages/neoscript-language/src/language-spec.ts"() {
|
|
1342
1342
|
"use strict";
|
|
@@ -1680,6 +1680,14 @@ var init_language_spec = __esm({
|
|
|
1680
1680
|
NEOSCRIPT_MATH_TYPE_ID = "builtin:Math";
|
|
1681
1681
|
MATH_INFERENCE_RULE = "Accepts int, float, or decimal; the result mirrors the widest argument type.";
|
|
1682
1682
|
MATH_INTEGRAL_RULE = "Accepts int, float, or decimal; int and float return int, decimal returns decimal.";
|
|
1683
|
+
NEOSCRIPT_LIST_TYPE_NAME = "List";
|
|
1684
|
+
NEOSCRIPT_LIST_TYPE_ID = "builtin:List";
|
|
1685
|
+
NEOSCRIPT_LIST_REPEAT_NAME = "Repeat";
|
|
1686
|
+
LIST_ENTRY_TYPE = {
|
|
1687
|
+
kind: "typeParameter",
|
|
1688
|
+
id: `${NEOSCRIPT_LIST_TYPE_ID}:entry`,
|
|
1689
|
+
name: "T"
|
|
1690
|
+
};
|
|
1683
1691
|
NEOSCRIPT_BUILTIN_TYPE_SYMBOLS = [
|
|
1684
1692
|
{
|
|
1685
1693
|
id: "builtin:SpriteInfo",
|
|
@@ -1833,6 +1841,27 @@ var init_language_spec = __esm({
|
|
|
1833
1841
|
static: true
|
|
1834
1842
|
}
|
|
1835
1843
|
]
|
|
1844
|
+
},
|
|
1845
|
+
{
|
|
1846
|
+
id: NEOSCRIPT_LIST_TYPE_ID,
|
|
1847
|
+
name: NEOSCRIPT_LIST_TYPE_NAME,
|
|
1848
|
+
kind: "builtin",
|
|
1849
|
+
documentation: "The ordered collection type. Write List<T> to annotate, and bare List to reach its static factories.",
|
|
1850
|
+
members: [
|
|
1851
|
+
{
|
|
1852
|
+
id: `${NEOSCRIPT_LIST_TYPE_ID}:function:${NEOSCRIPT_LIST_REPEAT_NAME}`,
|
|
1853
|
+
name: NEOSCRIPT_LIST_REPEAT_NAME,
|
|
1854
|
+
kind: "function",
|
|
1855
|
+
type: { kind: "list", elementType: LIST_ENTRY_TYPE },
|
|
1856
|
+
returnType: { kind: "list", elementType: LIST_ENTRY_TYPE },
|
|
1857
|
+
parameters: [
|
|
1858
|
+
parameter("value", LIST_ENTRY_TYPE),
|
|
1859
|
+
parameter("count", INT_TYPE)
|
|
1860
|
+
],
|
|
1861
|
+
documentation: "Returns a list of count copies of value. The entry type is inferred from value and the assignment context \u2014 never spell it. value is evaluated exactly once, then count exactly once, so a reference-typed value is the same reference in every entry; count must be a non-negative int, and 0 produces an empty list.",
|
|
1862
|
+
static: true
|
|
1863
|
+
}
|
|
1864
|
+
]
|
|
1836
1865
|
}
|
|
1837
1866
|
];
|
|
1838
1867
|
}
|
|
@@ -6975,6 +7004,9 @@ var init_strict_parser = __esm({
|
|
|
6975
7004
|
if (t.kind === "keyword" && t.text === "Dictionary") {
|
|
6976
7005
|
return true;
|
|
6977
7006
|
}
|
|
7007
|
+
if (t.kind === "keyword" && (t.text === "List" || t.text === "Set") && this.peek(1).kind === "op" && this.peek(1).text === "<") {
|
|
7008
|
+
return true;
|
|
7009
|
+
}
|
|
6978
7010
|
if (t.kind !== "ident") return false;
|
|
6979
7011
|
let j = this.i + 1;
|
|
6980
7012
|
const tk = (k) => this.tokens[k];
|
|
@@ -7233,6 +7265,15 @@ var init_strict_parser = __esm({
|
|
|
7233
7265
|
let expr = this.parsePrimary();
|
|
7234
7266
|
while (true) {
|
|
7235
7267
|
const t = this.peek();
|
|
7268
|
+
if (t.kind === "op" && t.text === "<" && expr.kind === "ident" && expr.name === NEOSCRIPT_LIST_TYPE_NAME) {
|
|
7269
|
+
const member = this.genericStaticMemberName();
|
|
7270
|
+
if (member !== null) {
|
|
7271
|
+
throw new CompileError(
|
|
7272
|
+
`Do not spell type arguments on '${NEOSCRIPT_LIST_TYPE_NAME}.${member}'; the entry type is inferred from the value.`,
|
|
7273
|
+
t.pos
|
|
7274
|
+
);
|
|
7275
|
+
}
|
|
7276
|
+
}
|
|
7236
7277
|
if (t.kind === "op" && t.text === "<" && this.looksLikeGenericCall()) {
|
|
7237
7278
|
this.next();
|
|
7238
7279
|
const typeArguments = [this.parseType()];
|
|
@@ -7322,6 +7363,28 @@ var init_strict_parser = __esm({
|
|
|
7322
7363
|
return expr;
|
|
7323
7364
|
}
|
|
7324
7365
|
}
|
|
7366
|
+
/**
|
|
7367
|
+
* The member name in a `<T, …>.Member` spelling at the cursor, or `null`
|
|
7368
|
+
* when the `<` is an ordinary comparison. Type arguments never precede a
|
|
7369
|
+
* member access in NeoScript, so this shape is always an author mistake and
|
|
7370
|
+
* the name is what a diagnostic needs to describe it.
|
|
7371
|
+
*/
|
|
7372
|
+
genericStaticMemberName() {
|
|
7373
|
+
const open = this.tokens[this.i];
|
|
7374
|
+
if (open?.kind !== "op" || open.text !== "<") return null;
|
|
7375
|
+
let index = this.scanType(this.i + 1);
|
|
7376
|
+
if (index === null) return null;
|
|
7377
|
+
while (this.tokens[index]?.kind === "punct" && this.tokens[index]?.text === ",") {
|
|
7378
|
+
index = this.scanType(index + 1);
|
|
7379
|
+
if (index === null) return null;
|
|
7380
|
+
}
|
|
7381
|
+
const close = this.tokens[index];
|
|
7382
|
+
const dot = this.tokens[index + 1];
|
|
7383
|
+
const member = this.tokens[index + 2];
|
|
7384
|
+
if (close?.kind !== "op" || close.text !== ">") return null;
|
|
7385
|
+
if (dot?.kind !== "punct" || dot.text !== ".") return null;
|
|
7386
|
+
return member?.kind === "ident" ? member.text : null;
|
|
7387
|
+
}
|
|
7325
7388
|
looksLikeGenericCall() {
|
|
7326
7389
|
const open = this.tokens[this.i];
|
|
7327
7390
|
if (open?.kind !== "op" || open.text !== "<") return false;
|
|
@@ -9431,7 +9494,7 @@ function switchValueKey(value) {
|
|
|
9431
9494
|
const enumId = value.typeInfo.type === 8 /* Enum */ ? value.typeInfo.enumId : null;
|
|
9432
9495
|
return JSON.stringify([value.typeInfo.type, enumId, value.value]);
|
|
9433
9496
|
}
|
|
9434
|
-
var CONSTRUCTING_FUNCTION_KINDS, VARIANT_INITIALIZE_NAME, VARIANT_APPLY_NAME, MATH_NAMESPACE_NAME, MATH_FUNCTIONS, MATH_CONSTANTS, WRITE_TARGET_DESCRIPTIONS, FALLTHROUGH_LABELS, Scope, StrictNeoScriptResolver, SPRITE_DERIVED_MEMBERS;
|
|
9497
|
+
var CONSTRUCTING_FUNCTION_KINDS, VARIANT_INITIALIZE_NAME, VARIANT_APPLY_NAME, MATH_NAMESPACE_NAME, MATH_FUNCTIONS, MATH_CONSTANTS, LIST_STATIC_FUNCTIONS, WRITE_TARGET_DESCRIPTIONS, FALLTHROUGH_LABELS, Scope, StrictNeoScriptResolver, SPRITE_DERIVED_MEMBERS;
|
|
9435
9498
|
var init_strict_resolver = __esm({
|
|
9436
9499
|
"../packages/neoscript-language/src/strict-resolver.ts"() {
|
|
9437
9500
|
"use strict";
|
|
@@ -9472,6 +9535,9 @@ var init_strict_resolver = __esm({
|
|
|
9472
9535
|
["PI", 3.141592653589793],
|
|
9473
9536
|
["E", 2.718281828459045]
|
|
9474
9537
|
]);
|
|
9538
|
+
LIST_STATIC_FUNCTIONS = /* @__PURE__ */ new Map([
|
|
9539
|
+
[NEOSCRIPT_LIST_REPEAT_NAME, { arity: 2 }]
|
|
9540
|
+
]);
|
|
9475
9541
|
WRITE_TARGET_DESCRIPTIONS = {
|
|
9476
9542
|
this: "`this`",
|
|
9477
9543
|
local: "a local",
|
|
@@ -11123,7 +11189,8 @@ var init_strict_resolver = __esm({
|
|
|
11123
11189
|
expression.callee,
|
|
11124
11190
|
expression.args,
|
|
11125
11191
|
scope,
|
|
11126
|
-
expression.pos
|
|
11192
|
+
expression.pos,
|
|
11193
|
+
expected
|
|
11127
11194
|
);
|
|
11128
11195
|
case "new": {
|
|
11129
11196
|
const vector = this.targetTypedVectorKind(expression, expected);
|
|
@@ -11770,6 +11837,12 @@ var init_strict_resolver = __esm({
|
|
|
11770
11837
|
pos
|
|
11771
11838
|
);
|
|
11772
11839
|
}
|
|
11840
|
+
if (name === NEOSCRIPT_LIST_TYPE_NAME) {
|
|
11841
|
+
throw new CompileError(
|
|
11842
|
+
`'${NEOSCRIPT_LIST_TYPE_NAME}' is a type and cannot be used as a value.`,
|
|
11843
|
+
pos
|
|
11844
|
+
);
|
|
11845
|
+
}
|
|
11773
11846
|
const type = this.project.typeByName.get(name);
|
|
11774
11847
|
if (type?.kind === "enum") {
|
|
11775
11848
|
return {
|
|
@@ -12222,6 +12295,15 @@ var init_strict_resolver = __esm({
|
|
|
12222
12295
|
}
|
|
12223
12296
|
return this.resolveMathMemberRead(name, pos);
|
|
12224
12297
|
}
|
|
12298
|
+
if (receiverAst.name === NEOSCRIPT_LIST_TYPE_NAME) {
|
|
12299
|
+
if (optional) {
|
|
12300
|
+
throw new CompileError(
|
|
12301
|
+
`Optional chaining is not valid on type '${NEOSCRIPT_LIST_TYPE_NAME}'.`,
|
|
12302
|
+
pos
|
|
12303
|
+
);
|
|
12304
|
+
}
|
|
12305
|
+
return this.resolveListStaticMemberRead(name, pos);
|
|
12306
|
+
}
|
|
12225
12307
|
const staticType = this.project.typeByName.get(receiverAst.name);
|
|
12226
12308
|
if (staticType && staticType.kind !== "enum") {
|
|
12227
12309
|
if (optional) {
|
|
@@ -12851,7 +12933,97 @@ var init_strict_resolver = __esm({
|
|
|
12851
12933
|
)
|
|
12852
12934
|
};
|
|
12853
12935
|
}
|
|
12854
|
-
|
|
12936
|
+
/**
|
|
12937
|
+
* P71 §1.2. A member read on the `List` qualifier. Nothing on `List` is
|
|
12938
|
+
* readable as a value: the statics are functions, and there are no
|
|
12939
|
+
* constants.
|
|
12940
|
+
*/
|
|
12941
|
+
resolveListStaticMemberRead(name, pos) {
|
|
12942
|
+
if (LIST_STATIC_FUNCTIONS.has(name)) {
|
|
12943
|
+
throw new CompileError(
|
|
12944
|
+
`'${NEOSCRIPT_LIST_TYPE_NAME}.${name}' must be called with \`()\`; it cannot be read as a value.`,
|
|
12945
|
+
pos
|
|
12946
|
+
);
|
|
12947
|
+
}
|
|
12948
|
+
throw new CompileError(
|
|
12949
|
+
`'${NEOSCRIPT_LIST_TYPE_NAME}' has no static member '${name}'.`,
|
|
12950
|
+
pos
|
|
12951
|
+
);
|
|
12952
|
+
}
|
|
12953
|
+
/** P71 §1.1. A static-factory call on the bare `List` qualifier. */
|
|
12954
|
+
resolveListStaticCall(name, args, scope, expected, pos) {
|
|
12955
|
+
const fn = LIST_STATIC_FUNCTIONS.get(name);
|
|
12956
|
+
if (!fn) {
|
|
12957
|
+
throw new CompileError(
|
|
12958
|
+
`'${NEOSCRIPT_LIST_TYPE_NAME}' has no static member '${name}'.`,
|
|
12959
|
+
pos
|
|
12960
|
+
);
|
|
12961
|
+
}
|
|
12962
|
+
requireArgCount(`${NEOSCRIPT_LIST_TYPE_NAME}.${name}`, args, fn.arity, pos);
|
|
12963
|
+
return this.resolveListRepeat(args, scope, expected);
|
|
12964
|
+
}
|
|
12965
|
+
/**
|
|
12966
|
+
* P71 §2/§3. `List.Repeat(value, count)`: the entry type is the value's
|
|
12967
|
+
* type joined with the contextual entry type — the list-literal join,
|
|
12968
|
+
* numeric widening included — and the count is an `int` with no implicit
|
|
12969
|
+
* narrowing. Lowers to a `listRepeat` intrinsic carrying the value pointer,
|
|
12970
|
+
* the count pointer, and the joined entry type the evaluators must not
|
|
12971
|
+
* re-derive.
|
|
12972
|
+
*/
|
|
12973
|
+
resolveListRepeat(args, scope, expected) {
|
|
12974
|
+
const label = `${NEOSCRIPT_LIST_TYPE_NAME}.${NEOSCRIPT_LIST_REPEAT_NAME}`;
|
|
12975
|
+
const expectedEntry = expected?.kind === "list" ? expected.elementType : void 0;
|
|
12976
|
+
const valueAst = requiredAt(args, 0);
|
|
12977
|
+
const countAst = requiredAt(args, 1);
|
|
12978
|
+
const value = this.resolveExpression(valueAst, scope, expectedEntry);
|
|
12979
|
+
const count = this.resolveExpression(countAst, scope, {
|
|
12980
|
+
kind: "primitive",
|
|
12981
|
+
name: "int"
|
|
12982
|
+
});
|
|
12983
|
+
if (isNullable(count.type)) {
|
|
12984
|
+
throw new CompileError(
|
|
12985
|
+
`${label} count must be a non-optional int; got ${this.describe(count.type)}.`,
|
|
12986
|
+
countAst.pos
|
|
12987
|
+
);
|
|
12988
|
+
}
|
|
12989
|
+
if (!isPrimitive(count.type, "int")) {
|
|
12990
|
+
throw new CompileError(
|
|
12991
|
+
`${label} count must be an int; got ${this.describe(count.type)}.`,
|
|
12992
|
+
countAst.pos
|
|
12993
|
+
);
|
|
12994
|
+
}
|
|
12995
|
+
const entryType = commonNeoScriptAssignableType(
|
|
12996
|
+
expectedEntry ?? value.type,
|
|
12997
|
+
value.type,
|
|
12998
|
+
this.project
|
|
12999
|
+
);
|
|
13000
|
+
if (entryType === null) {
|
|
13001
|
+
throw new CompileError(
|
|
13002
|
+
`${label} value ${this.describe(value.type)} is not a ${this.describe(expectedEntry ?? value.type)} entry.`,
|
|
13003
|
+
valueAst.pos
|
|
13004
|
+
);
|
|
13005
|
+
}
|
|
13006
|
+
const type = {
|
|
13007
|
+
kind: "list",
|
|
13008
|
+
elementType: entryType
|
|
13009
|
+
};
|
|
13010
|
+
const wire = toWireType(type, this.project);
|
|
13011
|
+
if (wire.type !== 6 /* List */) {
|
|
13012
|
+
throw new Error(
|
|
13013
|
+
"NeoScript strict compiler produced a non-list wire type for List.Repeat."
|
|
13014
|
+
);
|
|
13015
|
+
}
|
|
13016
|
+
return intrinsic(
|
|
13017
|
+
"listRepeat" /* ListRepeat */,
|
|
13018
|
+
{
|
|
13019
|
+
valuePointer: value.pointer,
|
|
13020
|
+
countPointer: count.pointer,
|
|
13021
|
+
entryTypeInfo: wire.entryTypeInfo
|
|
13022
|
+
},
|
|
13023
|
+
type
|
|
13024
|
+
);
|
|
13025
|
+
}
|
|
13026
|
+
resolveCall(callee, argumentsList2, scope, pos, expected) {
|
|
12855
13027
|
const variantCall = this.resolveVariantCall(
|
|
12856
13028
|
callee,
|
|
12857
13029
|
argumentsList2,
|
|
@@ -12953,6 +13125,21 @@ var init_strict_resolver = __esm({
|
|
|
12953
13125
|
}
|
|
12954
13126
|
return this.resolveMathCall(callee.name, argumentsList2, scope, pos);
|
|
12955
13127
|
}
|
|
13128
|
+
if (callee.receiver.name === NEOSCRIPT_LIST_TYPE_NAME) {
|
|
13129
|
+
if (callee.optional) {
|
|
13130
|
+
throw new CompileError(
|
|
13131
|
+
`Optional chaining is not valid on type '${NEOSCRIPT_LIST_TYPE_NAME}'.`,
|
|
13132
|
+
pos
|
|
13133
|
+
);
|
|
13134
|
+
}
|
|
13135
|
+
return this.resolveListStaticCall(
|
|
13136
|
+
callee.name,
|
|
13137
|
+
argumentsList2,
|
|
13138
|
+
scope,
|
|
13139
|
+
expected,
|
|
13140
|
+
pos
|
|
13141
|
+
);
|
|
13142
|
+
}
|
|
12956
13143
|
const staticType = this.project.typeByName.get(callee.receiver.name);
|
|
12957
13144
|
if (staticType && staticType.kind !== "enum") {
|
|
12958
13145
|
if (callee.optional) {
|
|
@@ -18575,7 +18762,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
18575
18762
|
"../packages/neoscript-language/src/project-schema-contract.generated.ts"() {
|
|
18576
18763
|
"use strict";
|
|
18577
18764
|
PROJECT_SCHEMA_MANIFEST_FORMAT_VERSION = 3;
|
|
18578
|
-
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.
|
|
18765
|
+
PROJECT_SCHEMA_MANIFEST_CONTRACT_VERSION = "3.14";
|
|
18579
18766
|
PROJECT_FILE_UPLOAD_BATCH_SIZE = 32;
|
|
18580
18767
|
NEO_PROJECT_SOURCE_RECORD_CONTRACT = {
|
|
18581
18768
|
"recordFields": {
|
|
@@ -18617,7 +18804,7 @@ var init_project_schema_contract_generated = __esm({
|
|
|
18617
18804
|
"collectionValueId",
|
|
18618
18805
|
"declaredTypeInfo",
|
|
18619
18806
|
"targetTypeInfo",
|
|
18620
|
-
"
|
|
18807
|
+
"valueTypeInfo",
|
|
18621
18808
|
"dialogueGroupId",
|
|
18622
18809
|
"code",
|
|
18623
18810
|
"setterCode",
|
|
@@ -20747,10 +20934,20 @@ var init_project_source_construction_diagnostics = __esm({
|
|
|
20747
20934
|
});
|
|
20748
20935
|
|
|
20749
20936
|
// ../packages/neoscript-language/src/project-source-variants.ts
|
|
20937
|
+
function neoLookupVariantFolderArgument(expression, name) {
|
|
20938
|
+
const index = expression.args.findIndex((_, argumentIndex) => {
|
|
20939
|
+
const authoredName = expression.argumentNames?.[argumentIndex];
|
|
20940
|
+
return (authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[argumentIndex]?.name ?? null) === name;
|
|
20941
|
+
});
|
|
20942
|
+
return index < 0 ? void 0 : expression.args[index];
|
|
20943
|
+
}
|
|
20750
20944
|
function neoVariantConstructionSiteCall(className, argumentNames, initializerNames) {
|
|
20751
20945
|
if (className === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME) {
|
|
20946
|
+
const logicalNames = argumentNames.map(
|
|
20947
|
+
(name, index) => name ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name ?? null
|
|
20948
|
+
);
|
|
20752
20949
|
return {
|
|
20753
|
-
argumentNames:
|
|
20950
|
+
argumentNames: logicalNames.filter(
|
|
20754
20951
|
(name) => name !== "collection" && name !== "collectionValue"
|
|
20755
20952
|
),
|
|
20756
20953
|
initializerNames
|
|
@@ -20814,21 +21011,14 @@ function neoVariantFolderAnnotationSymbol(annotations) {
|
|
|
20814
21011
|
function folderPath(declaration) {
|
|
20815
21012
|
const expression = parseInitializer(declaration);
|
|
20816
21013
|
if (expression === null || expression.kind !== "new") return null;
|
|
20817
|
-
const
|
|
20818
|
-
(name) => name === "path"
|
|
20819
|
-
);
|
|
20820
|
-
const argument2 = expression.args[pathIndex !== void 0 && pathIndex >= 0 ? pathIndex : 0];
|
|
21014
|
+
const argument2 = neoLookupVariantFolderArgument(expression, "path");
|
|
20821
21015
|
if (argument2 === void 0 || argument2.kind !== "litString") return null;
|
|
20822
21016
|
return argument2.value;
|
|
20823
21017
|
}
|
|
20824
21018
|
function folderCollectionPath(declaration) {
|
|
20825
21019
|
const expression = parseInitializer(declaration);
|
|
20826
21020
|
if (expression === null || expression.kind !== "new") return null;
|
|
20827
|
-
const
|
|
20828
|
-
(name) => name === "collection"
|
|
20829
|
-
);
|
|
20830
|
-
if (index === void 0 || index < 0) return null;
|
|
20831
|
-
const argument2 = expression.args[index];
|
|
21021
|
+
const argument2 = neoLookupVariantFolderArgument(expression, "collection");
|
|
20832
21022
|
if (argument2 === void 0) return null;
|
|
20833
21023
|
const parts = [];
|
|
20834
21024
|
let cursor = argument2;
|
|
@@ -21559,7 +21749,7 @@ function variantDiagnostic(entry, range2, code, message) {
|
|
|
21559
21749
|
message
|
|
21560
21750
|
};
|
|
21561
21751
|
}
|
|
21562
|
-
var NEO_VARIANT_CONSTRUCTOR_ARGUMENTS, NEO_VARIANT_MEMBER_ARGUMENTS, dottedScope;
|
|
21752
|
+
var NEO_VARIANT_CONSTRUCTOR_ARGUMENTS, NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS, NEO_VARIANT_MEMBER_ARGUMENTS, dottedScope;
|
|
21563
21753
|
var init_project_source_variants = __esm({
|
|
21564
21754
|
"../packages/neoscript-language/src/project-source-variants.ts"() {
|
|
21565
21755
|
"use strict";
|
|
@@ -21573,6 +21763,11 @@ var init_project_source_variants = __esm({
|
|
|
21573
21763
|
"overrides",
|
|
21574
21764
|
"childOverrides"
|
|
21575
21765
|
];
|
|
21766
|
+
NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS = [
|
|
21767
|
+
{ name: "path", type: "string" },
|
|
21768
|
+
{ name: "collection", type: "List<TValue>" },
|
|
21769
|
+
{ name: "collectionValue", type: "Reference<List<TValue>>" }
|
|
21770
|
+
];
|
|
21576
21771
|
NEO_VARIANT_MEMBER_ARGUMENTS = /* @__PURE__ */ new Map([
|
|
21577
21772
|
["overrides", "Overrides"],
|
|
21578
21773
|
["childOverrides", "ChildOverrides"]
|
|
@@ -23660,7 +23855,8 @@ function validateExpression(expression, expected, scope, environment, uri, range
|
|
|
23660
23855
|
) ?? [];
|
|
23661
23856
|
const overload = declaration && declaration.constructors.length > 0 ? matchingDeclaredConstructor(declaration, expression.argumentNames) : null;
|
|
23662
23857
|
expression.args.forEach((argument2, index) => {
|
|
23663
|
-
const
|
|
23858
|
+
const authoredName = expression.argumentNames?.[index];
|
|
23859
|
+
const named = declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME ? authoredName ?? NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS[index]?.name : authoredName;
|
|
23664
23860
|
if (declaration.name === NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME && named === "collection") {
|
|
23665
23861
|
return;
|
|
23666
23862
|
}
|
|
@@ -28816,11 +29012,7 @@ function projectConstructorArgumentCompletions(analysis, document, position) {
|
|
|
28816
29012
|
}
|
|
28817
29013
|
function lookupVariantFolderArgumentFields(typeName) {
|
|
28818
29014
|
if (typeName !== NEO_LOOKUP_VARIANT_FOLDER_TYPE_NAME) return null;
|
|
28819
|
-
return
|
|
28820
|
-
{ name: "path", type: "string" },
|
|
28821
|
-
{ name: "collection", type: "List<TValue>" },
|
|
28822
|
-
{ name: "collectionValue", type: "Reference<List<TValue>>" }
|
|
28823
|
-
];
|
|
29015
|
+
return NEO_LOOKUP_VARIANT_FOLDER_CONSTRUCTOR_ARGUMENTS;
|
|
28824
29016
|
}
|
|
28825
29017
|
function declaredConstructorNamedArguments(analysis, typeName, used) {
|
|
28826
29018
|
const contract = classConstructionContract(
|
|
@@ -34679,7 +34871,7 @@ var init_document_contracts = __esm({
|
|
|
34679
34871
|
"collectionValueId",
|
|
34680
34872
|
"declaredTypeInfo",
|
|
34681
34873
|
"targetTypeInfo",
|
|
34682
|
-
"
|
|
34874
|
+
"valueTypeInfo",
|
|
34683
34875
|
"dialogueGroupId",
|
|
34684
34876
|
"code",
|
|
34685
34877
|
"setterCode",
|
|
@@ -34718,6 +34910,7 @@ var init_document_contracts = __esm({
|
|
|
34718
34910
|
collectionValueId: "missingIsNullOnFullMember",
|
|
34719
34911
|
declaredTypeInfo: "nullIsAbsent",
|
|
34720
34912
|
targetTypeInfo: "nullIsAbsent",
|
|
34913
|
+
valueTypeInfo: "nullIsAbsent",
|
|
34721
34914
|
dialogueGroupId: "missingIsNullOnFullMember",
|
|
34722
34915
|
templateId: "missingIsNullOnFullMember",
|
|
34723
34916
|
setterCode: "nullIsAbsent",
|
|
@@ -36148,10 +36341,10 @@ function memberFromDocument(record3, members, owners, classNames, context) {
|
|
|
36148
36341
|
record3,
|
|
36149
36342
|
"targetTypeInfo"
|
|
36150
36343
|
),
|
|
36151
|
-
valueType: field("
|
|
36152
|
-
field("
|
|
36344
|
+
valueType: field("valueTypeInfo", null) === null ? null : documentTypeToManifest(
|
|
36345
|
+
field("valueTypeInfo", void 0),
|
|
36153
36346
|
record3,
|
|
36154
|
-
"
|
|
36347
|
+
"valueTypeInfo"
|
|
36155
36348
|
)
|
|
36156
36349
|
};
|
|
36157
36350
|
}
|
|
@@ -36301,7 +36494,7 @@ function memberToDocumentFields(member, baseData3) {
|
|
|
36301
36494
|
}
|
|
36302
36495
|
if (member.kind === "variant") {
|
|
36303
36496
|
fields.targetTypeInfo = manifestTypeToDocument(member.targetType);
|
|
36304
|
-
fields.
|
|
36497
|
+
fields.valueTypeInfo = member.valueType === null ? null : manifestTypeToDocument(member.valueType);
|
|
36305
36498
|
}
|
|
36306
36499
|
if (member.kind === "generic") {
|
|
36307
36500
|
fields.genericParamId = member.genericParamId;
|
|
@@ -39505,10 +39698,10 @@ function assertMember2(value, path) {
|
|
|
39505
39698
|
member.valueType,
|
|
39506
39699
|
`${path}.valueType`
|
|
39507
39700
|
).kind;
|
|
39508
|
-
if (valueKind !== "class") {
|
|
39701
|
+
if (valueKind !== "class" && valueKind !== "generic") {
|
|
39509
39702
|
invalid(
|
|
39510
39703
|
`${path}.valueType.kind`,
|
|
39511
|
-
"a lookup variant member's TValue must be a collection entry class."
|
|
39704
|
+
"a lookup variant member's TValue must be a collection entry class or an open generic parameter."
|
|
39512
39705
|
);
|
|
39513
39706
|
}
|
|
39514
39707
|
}
|
|
@@ -42486,6 +42679,19 @@ function isNSFunctionMathOp(value) {
|
|
|
42486
42679
|
const decimal2 = info.decimal;
|
|
42487
42680
|
return decimal2 === void 0 || decimal2 === true;
|
|
42488
42681
|
}
|
|
42682
|
+
function isNSFunctionListRepeat(value) {
|
|
42683
|
+
const v = value;
|
|
42684
|
+
if (v?.type !== "listRepeat" /* listRepeat */) return false;
|
|
42685
|
+
const info = v.info;
|
|
42686
|
+
if (typeof info !== "object" || info === null) return false;
|
|
42687
|
+
if (!isNSPointer(info.valuePointer)) {
|
|
42688
|
+
return false;
|
|
42689
|
+
}
|
|
42690
|
+
if (!isNSPointer(info.countPointer)) {
|
|
42691
|
+
return false;
|
|
42692
|
+
}
|
|
42693
|
+
return isNSTypeInfo(info.entryTypeInfo);
|
|
42694
|
+
}
|
|
42489
42695
|
function isNSFunctionCount(value) {
|
|
42490
42696
|
const v = value;
|
|
42491
42697
|
if (v?.type !== "count" /* count */) return false;
|
|
@@ -42533,7 +42739,7 @@ function isNSFunction(value) {
|
|
|
42533
42739
|
return isNSFunctionClassConstructor(value) || isNSFunctionClassClone(value) || isNSFunctionListIndex(value) || isNSFunctionSelect(value) || isNSFunctionFirst(value) || isNSFunctionFirstOrDefault(value) || isNSFunctionWhere(value) || isNSFunctionContains(value) || // stringOp was missing from this chain since its introduction — a
|
|
42534
42740
|
// compiled getter using ToLower()/StartsWith() would fail pointer
|
|
42535
42741
|
// validation anywhere isNSFunction gates. Fixed alongside decimalOp.
|
|
42536
|
-
isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
|
|
42742
|
+
isNSFunctionStringOp(value) || isNSFunctionDecimalOp(value) || isNSFunctionMathOp(value) || isNSFunctionListRepeat(value) || isNSFunctionCount(value) || isNSFunctionVisitCount(value) || isNSFunctionHasVisited(value) || isNSFunctionVectorConstructor(value) || isNSFunctionImageSlice(value) || isNSFunctionVariantInitialize(value) || isNSFunctionVariantApply(value) || isNSFunctionDeclaredConstructor(value);
|
|
42537
42743
|
}
|
|
42538
42744
|
function isNSInstructionVariable(value) {
|
|
42539
42745
|
const v = value;
|
|
@@ -43954,6 +44160,11 @@ function isMemberVariantBase(value) {
|
|
|
43954
44160
|
if (v.targetTypeInfo.type !== 7 /* Class */ && v.targetTypeInfo.type !== 21 /* Generic */) {
|
|
43955
44161
|
return false;
|
|
43956
44162
|
}
|
|
44163
|
+
if (v.valueTypeInfo !== void 0 && v.valueTypeInfo !== null && (!isNSTypeInfo(v.valueTypeInfo) || // P68's concrete folder binding resolves to a Class, while an unclosed
|
|
44164
|
+
// owner class can still spell the same TValue as its Generic parameter.
|
|
44165
|
+
v.valueTypeInfo.type !== 7 /* Class */ && v.valueTypeInfo.type !== 21 /* Generic */)) {
|
|
44166
|
+
return false;
|
|
44167
|
+
}
|
|
43957
44168
|
const defaultValue = v.defaultValue;
|
|
43958
44169
|
if (defaultValue === void 0 || defaultValue === null) return true;
|
|
43959
44170
|
if (!isMemberValueBase(defaultValue)) return false;
|
|
@@ -60062,13 +60273,11 @@ function folderBinding(context, global) {
|
|
|
60062
60273
|
`Lookup variant folder ${global.name} must be declared with new(...).`
|
|
60063
60274
|
);
|
|
60064
60275
|
}
|
|
60065
|
-
const
|
|
60066
|
-
|
|
60067
|
-
|
|
60068
|
-
|
|
60069
|
-
|
|
60070
|
-
const collection = named.get("collection");
|
|
60071
|
-
const collectionValue = named.get("collectionValue");
|
|
60276
|
+
const collection = neoLookupVariantFolderArgument(expression, "collection");
|
|
60277
|
+
const collectionValue = neoLookupVariantFolderArgument(
|
|
60278
|
+
expression,
|
|
60279
|
+
"collectionValue"
|
|
60280
|
+
);
|
|
60072
60281
|
const collectionPath = collection === void 0 ? null : dottedPath(collection);
|
|
60073
60282
|
if (collectionPath === null) {
|
|
60074
60283
|
throw new Error(
|
|
@@ -69347,6 +69556,25 @@ function evalDecimalMathOp(info, fn, scope, ctx) {
|
|
|
69347
69556
|
rethrowDecimalError(error);
|
|
69348
69557
|
}
|
|
69349
69558
|
}
|
|
69559
|
+
function evalListRepeat(info, scope, ctx) {
|
|
69560
|
+
const value = evalPointer(info.valuePointer, scope, ctx);
|
|
69561
|
+
const count = numberArg(
|
|
69562
|
+
evalPointer(info.countPointer, scope, ctx),
|
|
69563
|
+
"List.Repeat count"
|
|
69564
|
+
);
|
|
69565
|
+
if (count < 0) {
|
|
69566
|
+
throw new NSGetterRuntimeError(
|
|
69567
|
+
`List.Repeat count must be non-negative; got ${count}.`
|
|
69568
|
+
);
|
|
69569
|
+
}
|
|
69570
|
+
consumeBudget(
|
|
69571
|
+
ctx,
|
|
69572
|
+
"producedCollectionEntries",
|
|
69573
|
+
count,
|
|
69574
|
+
"produced collection entry"
|
|
69575
|
+
);
|
|
69576
|
+
return new Array(count).fill(value);
|
|
69577
|
+
}
|
|
69350
69578
|
function stringifyForInterp(v) {
|
|
69351
69579
|
if (v === null || v === void 0) return "";
|
|
69352
69580
|
if (typeof v === "string") return v;
|
|
@@ -69868,6 +70096,8 @@ function evalFunction(fn, scope, ctx) {
|
|
|
69868
70096
|
}
|
|
69869
70097
|
case "mathOp" /* mathOp */:
|
|
69870
70098
|
return evalMathOp(fn.info, scope, ctx);
|
|
70099
|
+
case "listRepeat" /* listRepeat */:
|
|
70100
|
+
return evalListRepeat(fn.info, scope, ctx);
|
|
69871
70101
|
case "stringOp" /* stringOp */: {
|
|
69872
70102
|
const receiver = evalPointer(fn.info.receiverPointer, scope, ctx);
|
|
69873
70103
|
if (typeof receiver !== "string") {
|
|
@@ -112943,8 +113173,8 @@ var init_registry2 = __esm({
|
|
|
112943
113173
|
"use strict";
|
|
112944
113174
|
PROJECT_SCHEMA_CONTRACT = Object.freeze({
|
|
112945
113175
|
formatVersion: 3,
|
|
112946
|
-
contractVersion: "3.
|
|
112947
|
-
cliVersion: "0.
|
|
113176
|
+
contractVersion: "3.14",
|
|
113177
|
+
cliVersion: "0.34.1",
|
|
112948
113178
|
projectFileUploadBatchSize: 32,
|
|
112949
113179
|
documentRecords: {
|
|
112950
113180
|
member: {
|
|
@@ -112986,7 +113216,7 @@ var init_registry2 = __esm({
|
|
|
112986
113216
|
"collectionValueId",
|
|
112987
113217
|
"declaredTypeInfo",
|
|
112988
113218
|
"targetTypeInfo",
|
|
112989
|
-
"
|
|
113219
|
+
"valueTypeInfo",
|
|
112990
113220
|
"dialogueGroupId",
|
|
112991
113221
|
"code",
|
|
112992
113222
|
"setterCode",
|
|
@@ -113025,6 +113255,7 @@ var init_registry2 = __esm({
|
|
|
113025
113255
|
collectionValueId: "missingIsNullOnFullMember",
|
|
113026
113256
|
declaredTypeInfo: "nullIsAbsent",
|
|
113027
113257
|
targetTypeInfo: "nullIsAbsent",
|
|
113258
|
+
valueTypeInfo: "nullIsAbsent",
|
|
113028
113259
|
dialogueGroupId: "missingIsNullOnFullMember",
|
|
113029
113260
|
templateId: "missingIsNullOnFullMember",
|
|
113030
113261
|
setterCode: "nullIsAbsent",
|
|
@@ -114431,6 +114662,8 @@ function sharedEvaluatorBase(rawDocument) {
|
|
|
114431
114662
|
enums: document.enums,
|
|
114432
114663
|
interfaces: document.interfaces,
|
|
114433
114664
|
constructors,
|
|
114665
|
+
variants: document.variants,
|
|
114666
|
+
variantFolders: document.variantFolders,
|
|
114434
114667
|
projectFiles: document.projectFiles,
|
|
114435
114668
|
localizationConfig: document.localizationConfig,
|
|
114436
114669
|
localizedTexts: document.localizedTexts,
|
|
@@ -119543,7 +119776,7 @@ There is no --keep-current: preserving current semantic state defines flatten.
|
|
|
119543
119776
|
async function main() {
|
|
119544
119777
|
const args = parseArgs(process.argv.slice(2));
|
|
119545
119778
|
if (args.command === "--version") {
|
|
119546
|
-
console.log("0.
|
|
119779
|
+
console.log("0.34.1");
|
|
119547
119780
|
return;
|
|
119548
119781
|
}
|
|
119549
119782
|
if (args.command === null || args.command === "help" || args.command === "--help" || args.command === "-h") {
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
`@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
<!-- reviewed-through-cli: 0.
|
|
12
|
+
<!-- reviewed-through-cli: 0.34.1 -->
|
|
13
13
|
|
|
14
14
|
# Neo Compose CLI
|
|
15
15
|
|
|
@@ -138,8 +138,8 @@ completely before editing:
|
|
|
138
138
|
variant folders, partial animation overrides, segments, tracks, and NeoFlow
|
|
139
139
|
dialogues.
|
|
140
140
|
- [NeoScript](references/neoscript.md): inline bodies, snippets, nullability,
|
|
141
|
-
numeric builtins, loops, switch, try/catch, ownership, evaluation,
|
|
142
|
-
migrations.
|
|
141
|
+
numeric and list builtins, loops, switch, try/catch, ownership, evaluation,
|
|
142
|
+
and migrations.
|
|
143
143
|
- [Commands and synchronization](references/commands-and-sync.md): pull/push,
|
|
144
144
|
conflicts, low-level repair, branches, releases, and history.
|
|
145
145
|
- [CLI development](references/cli-development.md): implementation source of
|
|
@@ -83,7 +83,7 @@ wrappers.
|
|
|
83
83
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
84
84
|
|
|
85
85
|
```html
|
|
86
|
-
<!-- reviewed-through-cli: 0.
|
|
86
|
+
<!-- reviewed-through-cli: 0.34.1 -->
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -8,6 +8,7 @@ runtime ownership, evaluation, and migrations.
|
|
|
8
8
|
- Inline bodies and snippets
|
|
9
9
|
- Nullability and ownership
|
|
10
10
|
- Numeric builtins
|
|
11
|
+
- List builtins
|
|
11
12
|
- Conditional and logical operators
|
|
12
13
|
- Loops and transfer
|
|
13
14
|
- Switch
|
|
@@ -127,6 +128,31 @@ enum, parameter, or local may shadow it. Qualified members use their owner's
|
|
|
127
128
|
namespace and may be named `Math`; access one as `this.Math` or
|
|
128
129
|
`SomeValue.Math` without colliding with the builtin qualifier.
|
|
129
130
|
|
|
131
|
+
## List builtins
|
|
132
|
+
|
|
133
|
+
Use `List.Repeat(value, count)` to build a list of `count` copies of a value
|
|
134
|
+
instead of hand-counting a literal or looping around `Add`:
|
|
135
|
+
|
|
136
|
+
```neo
|
|
137
|
+
List<int> scores = List.Repeat(0, 10);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The entry type is inferred from the value and joined with the assignment
|
|
141
|
+
context, exactly like a list literal, so assigning `List.Repeat(0, 4)` to a
|
|
142
|
+
`List<float>` widens the entries to `float`. Never spell type arguments on the
|
|
143
|
+
qualifier: `List<int>.Repeat(0, 3)` is an error, and bare `List` is a
|
|
144
|
+
qualifier, not a value.
|
|
145
|
+
|
|
146
|
+
`count` must be an `int` — a `float` count is a compile error, and a negative
|
|
147
|
+
count fails at runtime with `List.Repeat count must be non-negative; got
|
|
148
|
+
{count}.`. A count of `0` produces an empty `List<T>` whose entry type is
|
|
149
|
+
still known. The value is evaluated exactly once, then the count exactly once,
|
|
150
|
+
so side effects happen once regardless of `count`, and every entry is that one
|
|
151
|
+
value: for a reference-typed entry the same reference repeats `count` times.
|
|
152
|
+
Materializing the list charges `count` to the shared collection-entries
|
|
153
|
+
execution budget, so a runaway count fails with the existing budget error
|
|
154
|
+
before allocating.
|
|
155
|
+
|
|
130
156
|
## Conditional and logical operators
|
|
131
157
|
|
|
132
158
|
Use `condition ? whenTrue : whenFalse` for a value chosen by a condition:
|