custom_scope_objects.js (2754B)
1 const { create, all } = require('../..') 2 3 const math = create(all) 4 5 // The expression evaluator accepts an optional scope object. 6 // This is the symbol table for variable defintions and function declations. 7 8 // Scope can be a bare object. 9 function withObjectScope () { 10 const scope = { x: 3 } 11 12 math.evaluate('x', scope) // 1 13 math.evaluate('y = 2 x', scope) 14 math.evaluate('scalar = 1', scope) 15 math.evaluate('area(length, width) = length * width * scalar', scope) 16 math.evaluate('A = area(x, y)', scope) 17 18 console.log('Object scope:', scope) 19 } 20 21 // Where flexibility is important, scope can duck type appear to be a Map. 22 function withMapScope (scope, name) { 23 scope.set('x', 3) 24 25 math.evaluate('x', scope) // 1 26 math.evaluate('y = 2 x', scope) 27 math.evaluate('scalar = 1', scope) 28 math.evaluate('area(length, width) = length * width * scalar', scope) 29 math.evaluate('A = area(x, y)', scope) 30 31 console.log(`Map-like scope (${name}):`, scope.localScope) 32 } 33 34 // This is a minimal set of functions to look like a Map. 35 class MapScope { 36 constructor () { 37 this.localScope = new Map() 38 } 39 40 get (key) { 41 // Remember to sanitize your inputs, or use 42 // a datastructure that isn't a footgun. 43 return this.localScope.get(key) 44 } 45 46 set (key, value) { 47 return this.localScope.set(key, value) 48 } 49 50 has (key) { 51 return this.localScope.has(key) 52 } 53 54 keys () { 55 return this.localScope.keys() 56 } 57 } 58 59 /* 60 * This is a more fully featured example, with all methods 61 * used in mathjs. 62 * 63 */ 64 class AdvancedMapScope extends MapScope { 65 constructor (parent) { 66 super() 67 this.parentScope = parent 68 } 69 70 get (key) { 71 return this.localScope.get(key) ?? this.parentScope?.get(key) 72 } 73 74 has (key) { 75 return this.localScope.has(key) ?? this.parentScope?.get(key) 76 } 77 78 keys () { 79 if (this.parentScope) { 80 return new Set([...this.localScope.keys(), ...this.parentScope.keys()]) 81 } else { 82 return this.localScope.keys() 83 } 84 } 85 86 delete () { 87 return this.localScope.delete() 88 } 89 90 clear () { 91 return this.localScope.clear() 92 } 93 94 /** 95 * Creates a child scope from this one. This is used in function calls. 96 * 97 * @returns a new Map scope that has access to the symbols in the parent, but 98 * cannot overwrite them. 99 */ 100 createSubScope () { 101 return new AdvancedMapScope(this) 102 } 103 104 toString () { 105 return this.localScope.toString() 106 } 107 } 108 109 withObjectScope() 110 // Where safety is important, scope can also be a Map 111 withMapScope(new Map(), 'simple Map') 112 // Where flexibility is important, scope can duck type appear to be a Map. 113 withMapScope(new MapScope(), 'MapScope example') 114 // Extra methods allow even finer grain control. 115 withMapScope(new AdvancedMapScope(), 'AdvancedScope example')