UNPKG

oppo

Version:

A lisp for javascript

267 lines (217 loc) 6.68 kB
root = global ? window root.oppo = root: root modules: {} oppo.oppo_undefined = {} class OppoCompileError extends Error constructor: (message, @form) -> @line_number = @form and @form.line_number if @line_number message = "at line #{@line_number}: #{message}" @message = message oppo.JavaScriptCode = class JavaScriptCode constructor: (@text) -> oppo.JavaScriptComment = class JavaScriptComment oppo.Symbol = class Symbol constructor: (text, base_symbol) -> @text = "#{text}" @line_number = base_symbol?.line_number ? reader.line_number toString: -> oppo.helpers.get_symbol_text this oppo.Splat = class Splat object_toString = Object::toString array_concat = Array::concat oppo.helpers = to_type: (o) -> (s = object_toString.call o).substring(8, s.length - 1).toLowerCase() clone: Object.create ? (o) -> class Noop Noop:: = o new Noop merge: (first_o = {}, objs...) -> for o in objs continue if not o? for own k, v of o first_o[k] = v first_o raise: (err) -> console.error err.toString() throw err to_oppo_string: (x, quote_strings = yes) -> {to_oppo_string, to_type} = oppo.helpers type = to_type x quoted = x?.quoted string = if not x? "#nil" else if type is "boolean" "##{x}" else if x instanceof oppo.Symbol x.text else if type is "array" items = (to_oppo_string item for item in x) quoted = yes "(#{items.join ' '})" else if type is "object" items = ("#{k} #{to_oppo_string v}" for k, v of x) "{ #{items.join '\n '} }" else if quote_strings and type is "string" "\"#{x}\"" else if type is "function" "#<Function #{x.name or '__anonymous__'}>" else if x.toString? x.toString() else "#{x}" if quoted string = "'#{string}" string first_item_matches: (x, sym) -> c_sym = get_symbol_text sym, yes if (to_type x) is "array" [fst] = x if is_symbol fst c_fst = get_symbol_text fst c_fst is c_sym else no else no # Include the fns that come after here symbol: (text, base_symbol) -> if text instanceof Symbol text else new Symbol text, base_symbol get_symbol: (sym) -> {to_type} = oppo.helpers type = to_type sym if (is_symbol sym) and type is "array" if is_quoted sym get_symbol sym[1] else sym[1] else if type is "string" (symbol sym) else if sym instanceof Symbol sym else throw new Error "Can't get symbol from non-symbol #{sym}" get_symbol_text: (sym, resolve_module = false, raw = false) -> {get_symbol, text_to_js_identifier} = oppo.helpers sym = get_symbol sym if sym instanceof Symbol if raw sym.text else text_to_js_identifier sym.text else throw new OppoCompileError "Can't get symbol text from non-symbol #{sym}", sym concat: (base, items...) -> if base.concat? base.concat items... else array_concat.apply base, items gensym: do -> gensym_id_map = {} gensym = (name = "gen") -> {symbol} = oppo.helpers id = gensym_id_map[name] if not id? id = gensym_id_map[name] = 0 ret = symbol "#{name}_#{id}__" gensym_id_map[name] += 1 ret get_module: do -> module_splitter = '::' get_module = (sym) -> {text_to_js_identifier, get_symbol_text, symbol} = oppo.helpers # module_splitter ?= text_to_js_identifier '::' s_sym = get_symbol_text sym, false, true a_sym = s_sym.split module_splitter switch a_sym.length when 1 [s_sym] = a_sym when 2 [module, s_sym] = a_sym else throw new OppoCompileError "Can't define more than one module for symbol #{s_sym}", sym [module, (symbol s_sym, sym)] is_symbol: (x, recurse = 1) -> {to_type, is_symbol} = oppo.helpers x instanceof Symbol or (recurse and (to_type x) is "array" and is_symbol (oppo.compile_list x, no), recurse - 1) is_quoted: (x, recurse = 2) -> {first_item_matches} = oppo.helpers x?.quoted or first_item_matches x, "quote" is_object: (x) -> {first_item_matches} = oppo.helpers x?.constructor is Object or first_item_matches x, "object" is_quasiquoted: (x, recurse = 2) -> {first_item_matches} = oppo.helpers x?.quasiquoted or first_item_matches x, "quasiquote" is_unquoted: (x, recurse = 2) -> {first_item_matches} = oppo.helpers x?.unquoted or first_item_matches x, "unquote" is_unquote_spliced: (x, recurse = 2) -> {first_item_matches} = oppo.helpers x?.unquote_spliced or first_item_matches x, "unquote-splicing" get_options: (args...) -> {is_object} = oppo.helpers if not is_object args[0] args.unshift {} else if (to_type args[0]) is "array" options = args.shift() options = oppo.eval options args.unshift options args is_equal: -> {to_type, keys, is_equal} = oppo.helpers loop_started = false for item, i in arguments if not loop_started prev_b = item loop_started = yes continue a = prev_b b = item prev_b = b continue if a is b continue if not a? and not b? type = type_a = to_type a type_b = to_type b if type_a isnt type_b return false if type in ["string", "number", "function"] return false else if type is "array" if a.length isnt b.length return false for item_a, j in item if not is_equal item_a, b[j] return false else if type is "object" if a instanceof Symbol and b instanceof Symbol if a.text isnt b.text return false else continue keys_a = keys a keys_b = keys b if keys_a.length isnt keys_b.length return false for key, item_a of a if not is_equal item_a, b[key] return false else if type is "regexp" if (a.source isnt b.source) or (a.global isnt b.global) or (a.multiline isnt b.multiline) or (a.ignoreCase isnt b.ignoreCase) return false else if type is "date" if a.toISOString() isnt b.toISOString() return false true map: (fn, ls) -> for item in ls fn item own_keys: Object.keys or (o) -> prop for own prop of o keys: (o) -> prop for prop of o if module?.exports? module.exports = oppo