@naanlang/naan 1.0.13 → 1.0.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naanlang/naan",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "author": "Richard C. Zulch",
5
5
  "description": "Naan™ software platform",
6
6
  "main": "./lib/core/naanlib.js",
@@ -32,6 +32,10 @@
32
32
  * `number -- float or integer
33
33
  * `url -- URL
34
34
  *
35
+ * Although the currency type is only treated as a text field for now, the intent is that these will
36
+ * match the RegEx /([A-Z]{3})(-?[0-9]+(?:[,.][0-9]+)?)/ so that the currency type and amount can be
37
+ * differentiated. Please see ISO 4217 for valid currency types.
38
+ *
35
39
  * Current options are:
36
40
  * {
37
41
  * languages: [
@@ -183,15 +187,15 @@ closure openSearchIndex(prosc, indexName, ioptions, local osin) {
183
187
  //
184
188
  // date
185
189
  //
186
- date: quote(
187
- textRawMF()
188
- )
190
+ date: quote({
191
+ type: "date"
192
+ })
189
193
  //
190
194
  // boolean
191
195
  //
192
- boolean: quote(
193
- textRawMF()
194
- )
196
+ boolean: quote({
197
+ type: "boolean"
198
+ })
195
199
  //
196
200
  // currency
197
201
  //
@@ -213,15 +217,15 @@ closure openSearchIndex(prosc, indexName, ioptions, local osin) {
213
217
  //
214
218
  // integer
215
219
  //
216
- integer: quote(
217
- textRawMF()
218
- )
220
+ integer: quote({
221
+ type: "long"
222
+ })
219
223
  //
220
224
  // number
221
225
  //
222
- number: quote(
223
- textRawMF()
224
- )
226
+ number: quote({
227
+ type: "float"
228
+ })
225
229
  //
226
230
  // url
227
231
  //
@@ -303,7 +307,6 @@ closure openSearchIndex(prosc, indexName, ioptions, local osin) {
303
307
  properties: makeMapping(fields)
304
308
  }
305
309
  })
306
- // printline("OpenSearchClient.create:\n${Dialect.print(params)}")
307
310
  prosc.request(indexName, {
308
311
  method: "PUT"
309
312
  putdata: params
@@ -500,7 +503,6 @@ closure OpenSearchClient(goptions, local oscl, prosc) {
500
503
  query.multi_match.fields = ["*"].concat(soptions.boost.fields.map(function (item) {
501
504
  item.concat("^${soptions.boost.level}")
502
505
  }))
503
- printline(Dialect.print(soptions.boost))
504
506
  if dictionary(soptions.qopts)
505
507
  query.multi_match = merge(query.multi_match, soptions.qopts)
506
508
  if dictionary(soptions.filter) {
@@ -357,7 +357,7 @@ closure DynaConverter(local conv) {
357
357
  //
358
358
  // condition dictionary:
359
359
  // {
360
- // key: <keyname, e.g. partition key name> // required
360
+ // key: <keyname, e.g. partition key name or path tuple> // required
361
361
  // "=": <expression> // exclusive of other comparisons
362
362
  // ">": <expression> // exclusive of other comparisons
363
363
  // "<": <expression> // exclusive of other comparisons
@@ -365,11 +365,12 @@ closure DynaConverter(local conv) {
365
365
  // beginsWith: <string-expression> // exclusive of other comparisons
366
366
  // ">=": <expression> // with <= or alone
367
367
  // "<=": <expression> // with >= or alone
368
+ // exists: <boolean> // keyname existence matches boolean
368
369
  // }
369
370
  //
370
371
 
371
372
  conv.createKeyExpression = function createKeyExpression(params, conds
372
- local attval, rangename, range, keyname, op, expr, rangex, arg1, arg2) {
373
+ local attval, attname, rangename, range, keyname, op, expr, rangex, arg1, arg2) {
373
374
 
374
375
  // dupeop
375
376
  //
@@ -382,14 +383,24 @@ closure DynaConverter(local conv) {
382
383
  // build the expression
383
384
  //
384
385
  attval = genAttributeValueAdder(params)
386
+ attname = genAttributeNameAdder(params)
385
387
  for `(rangename, ranges) in conds {
386
388
  if !array(ranges)
387
389
  ranges = [ranges]
388
390
  for range in ranges {
389
391
  rangex = false
390
- keyname = tostring(range.key)
392
+ if tuple(range.key) {
393
+ keyname = []
394
+ expr = range.key
395
+ while expr
396
+ keyname.push(attname(pop(expr)))
397
+ keyname = keyname.join(".")
398
+ }
399
+ else
400
+ keyname = tostring(range.key)
391
401
  if !keyname
392
402
  return (list(Error("key expression requires key name")))
403
+ keyname = attname(keyname)
393
404
  for `(op, expr) in range {
394
405
  if op == "key"
395
406
  continue
@@ -417,10 +428,16 @@ closure DynaConverter(local conv) {
417
428
  arg1 = rangex.1
418
429
  if rangex.0 == "between" {
419
430
  arg2 = rangex.2
420
- expr = keyname.concat(" between ", arg1, " and ", arg2)
431
+ expr = "${keyname} between ${arg1} and ${arg2}"
421
432
  }
422
433
  else if rangex.0 == "beginsWith"
423
- expr = "begins_with(".concat(keyname, ", ", arg1, ")")
434
+ expr = "begins_with(${keyname}, ${arg1})"
435
+ else if rangex.0 == "exists" {
436
+ if arg1
437
+ expr = "attribute_exists(${keyname})"
438
+ else
439
+ expr = "attribute_not_exists(${keyname})"
440
+ }
424
441
  else
425
442
  expr = keyname.concat(space, rangex.0, space, arg1)
426
443
  if params[rangename]
@@ -674,14 +691,26 @@ closure DynaTable(dyna, tablename, local table) {
674
691
 
675
692
  // getRecord
676
693
  //
677
- // Get a record from the table with the specified hash value, and optional range value.
694
+ // Get a record from the table with the specified hash value. The optional second argument can be
695
+ // the rangeValue of the item, or an options dictionary. Dictionary options include:
696
+ // {
697
+ // rangeValue: <range-key> // record's range key
698
+ // consistentRead: <boolean> // true to use consistent read
699
+ // }
700
+ // The result is a standard result tuple `(error, record).
701
+
678
702
  //
679
- table.getRecord = closure getRecord(hashValue, rangeValue, local params, pending) {
703
+ table.getRecord = closure getRecord(hashValue, options, local params, rangeValue, pending) {
680
704
  if preflightError(this)
681
705
  return
682
706
  params = {
683
707
  TableName: tablename
684
708
  }
709
+ if dictionary(options) {
710
+ rangeValue = options.rangeValue
711
+ params.ConsistentRead = options.consistentRead
712
+ } else
713
+ rangeValue = options
685
714
  params.Key = makeDynKey(list(hashValue, rangeValue))
686
715
  pending = new(nonce)
687
716
  dyna.aws.getItem(params, function(error, data) {
@@ -856,6 +885,7 @@ closure DynaTable(dyna, tablename, local table) {
856
885
  // reverse: <boolean> // reverse order
857
886
  // project: <array> // project only specified attributes
858
887
  // paging: <exclusive start key> // for paging; updated each call
888
+ // consistentRead: <boolean> // true to use consistent read
859
889
  // limit: <number> // maximum count of results
860
890
  // }
861
891
  //
@@ -902,6 +932,8 @@ closure DynaTable(dyna, tablename, local table) {
902
932
  params.ProjectionExpression = options.project.join(", ")
903
933
  if options.paging
904
934
  params.ExclusiveStartKey = options.paging
935
+ if options.consistentRead
936
+ params.ConsistentRead = options.consistentRead
905
937
  output = []
906
938
  `(error) = dynQueryPager(`query, params, options.limit, function(data) {
907
939
  if data.Count > 0
@@ -921,12 +953,13 @@ closure DynaTable(dyna, tablename, local table) {
921
953
  //
922
954
  // Options:
923
955
  // {
924
- // index: <string> // index name in table
925
- // filter: <key-expression> // conditions for items to return
926
- // attmap: <dictionary> // map attribute names to #shortcuts
927
- // project: <array> // project only specified attributes
928
- // paging: <exclusive start key> // for paging; updated each call
929
- // limit: <number> // maximum count of results
956
+ // index: <string> // index name in table
957
+ // filter: <key-expression> // conditions for items to return
958
+ // attmap: <dictionary> // map attribute names to #shortcuts
959
+ // project: <array> // project only specified attributes
960
+ // paging: <exclusive start key> // for paging; updated each call
961
+ // consistentRead: <boolean> // true to use consistent read
962
+ // limit: <number> // maximum count of results
930
963
  // }
931
964
  //
932
965
 
@@ -953,6 +986,8 @@ closure DynaTable(dyna, tablename, local table) {
953
986
  params.ProjectionExpression = options.project.join(", ")
954
987
  if options.paging
955
988
  params.ExclusiveStartKey = options.paging
989
+ if options.consistentRead
990
+ params.ConsistentRead = options.consistentRead
956
991
  output = []
957
992
  `(error) = dynQueryPager(`scan, params, options.limit, function(data) {
958
993
  if data.Count >= 0
@@ -319,10 +319,13 @@ RegisterTestCategory("core", [
319
319
  [ "eval(`(+ 4 3));", "7" ],
320
320
 
321
321
  [ "apply(`+, `(4 3));", "7" ],
322
-
322
+ [ "apply(getproc(`+), `(4, 3));", "7" ], // ensures that call takes a builtin as function
323
+ [ "apply(Number.parseInt, list('42'));", "42" ],
324
+
323
325
  [ "call(car(`+), 4, 3);", "7" ],
324
326
  [ "call(getproc(`+), 4, 3);", "7" ], // ensures that call takes a builtin as function
325
-
327
+ [ "call(Number.parseInt, '42');", "42" ],
328
+
326
329
  [ "list();>", "false" ],
327
330
  [ "list(3, 4, 5, `(6 7));>", "(3 4 5 (6 7))" ],
328
331
 
@@ -424,7 +427,7 @@ RegisterTestCategory("core", [
424
427
  [ "temp(2, `(1 2 3));>", "(2 3)|(2 3)" ],
425
428
  [ "function (ex1, lex1) { ex1+pop(lex1), print(lex1), lex1 }(2, `(1 2 3));>", "(2 3)|(2 3)" ],
426
429
  [ "quote(function (a)\n { f(b)-\ng(c) * h(d)\n });>", "(function lambda (a) (- (f b) (* (g c) (h d))))" ],
427
- [ "quote(function (a)\n { f(b)\n-g(c) * h(d)\n });>", "(function lambda (a) (- (f b) (* (g c) (h d))))" ],
430
+ [ "quote(function (a)\n { f(b)\\\n-g(c) * h(d)\n });>", "(function lambda (a) (- (f b) (* (g c) (h d))))" ],
428
431
 
429
432
  [ "tempo = temp.proc;>", "(function temp (ex1 lex1) (+ ex1 (pop lex1)) (print lex1) lex1)" ],
430
433
  [ "function temp(ex1) { ex1 * 2 };", "==> redefined: temp|temp" ],
@@ -589,7 +592,21 @@ RegisterTestCategory("core", [
589
592
  [ "bobby.sue(44);", "(44)(sue billy)/Dictionary{2}|(sam nevil bill)/(sue billy)|(\"sue\", \"billy\")" ],
590
593
  [ "keys(bobby);>", "(\"sue\" \"billy\")" ],
591
594
 
592
-
595
+ ["merge();", "{ }"],
596
+ ["merge({a:3});", "{ a: 3 }"],
597
+ ["merge({a:3,b:4});", "{ a: 3, b: 4 }"],
598
+ ["merge({a:3,b:4,c:5});", "{ a: 3, b: 4, c: 5 }"],
599
+ ["merge(`(a));", "{ }"],
600
+ ["merge({a:3}, `(a));", "{ }"],
601
+ ["merge({a:3,b:4}, `(a), {c:5});", "{ b: 4, c: 5 }"],
602
+ ["merge({a:3,b:4}, `(c), {c:5});", "{ a: 3, b: 4, c: 5 }"],
603
+ ["merge({a:3,b:4}, `(g), {c:5});", "{ a: 3, b: 4, c: 5 }"],
604
+ ["merge({true:a,false:b});", "{ true: a, false: a }"],
605
+ ["merge({true:a,false:b}, `(true));", "{ false: a }"],
606
+ ["oo={true:a}; oo[1.0/3]=`b; oo;", "{ true: a }|b|{ true: a, 0.3333333333333333: b }"],
607
+ ["merge(oo, list(1.0/3), {false:c});", "{ true: a, false: c }"],
608
+ ["oo;", "{ true: a, 0.3333333333333333: b }"],
609
+
593
610
  //
594
611
  // object getters
595
612
  //
@@ -796,6 +813,9 @@ RegisterTestCategory("core", [
796
813
  [ "cons(`a);>", "(a)" ],
797
814
  [ "cons(`a,`b);>", "(a . b)" ],
798
815
  [ "cons(`a,`b,`c);>", "(a b . c)" ],
816
+
817
+ [ "unintern(true) === true", "false"],
818
+
799
819
  [ "length(stacktrace());", "55" ],
800
820
 
801
821
  //
@@ -63,6 +63,15 @@ RegisterTestCategory("JSinterop", [
63
63
 
64
64
  [ "xnew(js.g.Promise, function() {});", "[object Promise]" ],
65
65
 
66
+ //
67
+ // Arrays
68
+ //
69
+
70
+ ["Array(3,4,5);", "[Array 3,4,5]"],
71
+ ["Array([3]);", "[Array [3]]"],
72
+ ["Array([3]).0;", "[Array 3]"],
73
+ ["Array([3]).0.0;", "3"],
74
+
66
75
 
67
76
  //
68
77
  // child processes
@@ -71,6 +71,6 @@ RegisterTestCategory("strings", [
71
71
  [ "\"abc\".toString();", "\"abc\"" ],
72
72
  [ "xapply(String, toString, list(\"abc\"));", "\"abc\"" ],
73
73
  [ "xcall(String, toString, \"abc\");", "\"abc\"" ],
74
- [ "function(local match) { \"abc\".match(RegExp(\"abc\")) }();", "[Array abc]" ]
74
+ [ "function(local match) { \"abc\".match(RegExp(\"abc\")) }();", '[Array "abc"]' ]
75
75
 
76
76
  ]);
@@ -61,7 +61,7 @@ RegisterTestCategory("Lingo parse", [
61
61
  //
62
62
 
63
63
  [ "4&&3;", { exprs: "(&& 4 3)" } ],
64
- [ "4\n&&3;", { exprs: "(&& 4 3)" } ],
64
+ [ "4\\\n&&3;", { exprs: "(&& 4 3)" } ],
65
65
  [ "4&&\n3;", { exprs: "(&& 4 3)" } ],
66
66
  [ "function test0(x, y) { \n y = 3\n x \n };", { exprs: "(defproc function test0 (x y) (= y 3) x)" } ],
67
67
 
@@ -468,7 +468,7 @@ RegisterTestCategory("Lingo parse", [
468
468
  //
469
469
 
470
470
  [ "function() {test()[3]};>", "(function lambda false (deref (test) 3))"],
471
- [ "function() {test()\n[3]};>", "(function lambda false (deref (test) 3))"],
471
+ [ "function() {test()\\\n[3]};>", "(function lambda false (deref (test) 3))"],
472
472
  [ "function() {test(),\n[3]};>", "(function lambda false (test) Array[1])"],
473
473
  [ "function() {test(),\n[3]};", "function () {\n"
474
474
  " test(),\n" // need comma before array
@@ -497,6 +497,28 @@ RegisterTestCategory("Lingo parse", [
497
497
  " else {\n"
498
498
  " { a: 3 } }\n" // need braces around dictionary
499
499
  "}" ],
500
+ [ "function() {if 1, -2 };", "function () {\n"
501
+ " if 1\n"
502
+ " -2\n"
503
+ "}" ],
504
+ [ "function() {if 1,\n"
505
+ "-2 };", "function () {\n"
506
+ " if 1\n"
507
+ " -2\n"
508
+ "}" ],
509
+ [ "function() {if 1\n"
510
+ "-2 };",
511
+ { errors: "ambiguous newline (use \\ or ,) at (2, 1) found -" } ],
512
+ [ "function() {if 1\\\n"
513
+ "-2 3 };", "function () {\n"
514
+ " if 1 - 2\n"
515
+ " 3\n"
516
+ "}" ],
517
+ [ "function() { else };",
518
+ { errors: "stray keyword at (1, 14) found else" } ],
519
+ [ "function() { if 1 else 3 };",
520
+ { errors: "stray keyword at (1, 19) found else"
521
+ "|mismatched delimiter at (1, 24) found 3 expected } starting with { at (1, 12)" } ],
500
522
 
501
523
  //
502
524
  // semantic validity
@@ -159,15 +159,25 @@ RegisterTestCategory("Lingo", [
159
159
  // " map : [(0, 23), 0, 9, 2, 7],\n" -- maps currently omitted
160
160
  " comments : [] } }" ],
161
161
  [ "testat@jim(true);", "\"you are annotated with true!\"" ],
162
+ [ "copyann(testat, a);", "testat" ],
163
+ [ "testat@*;", '("joe", "jim", ".sourcemap")' ],
164
+ [ "copyann(testat, a, true);", "testat" ],
165
+ [ "testat@*;", '("joe")' ],
166
+ [ "copyann(3, a);", { errors: "attempt to modify constant 3" } ],
167
+ [ "copyann(a, 3);", "false" ],
162
168
 
163
169
 
164
170
  //
165
- // lists, objects & arrays
171
+ // lists, dictionaries, objects, and arrays
166
172
  //
167
173
 
168
174
  [ "divide(71, 3);", "(23 . 2)" ],
169
175
  [ "[3,4+5];", "[3, 9]" ],
170
176
  [ "{a:3,b:4+5};", "{ a: 3, b: 9 }" ],
177
+ [ "function(g) { { a: 3+g } }(5);", "{ a: 8 }" ],
178
+ [ "function(g) { { a: false || undefined } }(6);", "{ }" ],
179
+ [ "function(g) { { a: false && g || undefined } }(7);", "{ }" ],
180
+ [ "function(g) { { a: true && g || undefined } }(8);", "{ a: 8 }" ],
171
181
 
172
182
  [ "`(1, 2, {a:3,b:4}, 5);", "(1, 2, { a: 3, b: 4 }, 5)" ],
173
183
  [ "`(1, 2, {a:3,b:4}, 5);>", "(1 2 Dictionary{2} 5)" ],