Guest User

Untitled

a guest
May 24th, 2018
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.84 KB | None | 0 0
  1. - Add an `ASSERT0()` macro, for things like `strcmp(3)` that return-0-on-success
  2. ✓ Test that `Magazine->set()`’s argument, and the return value of `Magazine->get()`’s setter callback, are the
  3. right `kind`
  4. ✓ Remove the `bytes` arguments to all the `String` methods; determine length from `'\0'`.
  5. ✓ Remove concept of extension; no need for `string` to be able to change length, thus, no need to store the
  6. number of ‘available’ bytes.
  7. ✓ Implement `String->embody()` to acquire a `string` from the appropriate `magazine`
  8. ✓ Switch the `magazine` tests to using `String->allocate()`, since it’s not going to attempt to use the uniques
  9. store, and thus no recursive dependency will be created any more
  10. ✗ Assemble a reverse mapping of `pthread_t` ID types to `thread` pointers, so we can get the current `thread` via
  11. `pthread_self()`
  12. - Doubly-link `pool`s back to the `unit` they belong to
  13. - Provide a way to get the “current” IU: get current `thread` via Pthreads, get the `pool` that the `thread`
  14. belongs to, get the IU that that `pool` belongs to
  15. - Get current IU’s `magazine` uniques-store for `string`s, and use that if the `magazine` passed to
  16. `String->embody()` is `NULL`
  17.  
  18. - Scrap current `routine` and `execution`, and start from scratch.
  19. - We have plans to make to make this possible… what system, exactly, are we going to set in place for all this?
  20. Specifics are needed! The changes re: futures-y stuff, `ghost`s and possibly `fork`s and so on… everything’s
  21. a bit up-in-the-air.
  22.  
  23. - Properly test `Thread->allocate()` by wrapping a `pthread_getspecific(3)` call into a native `routine` and
  24. adding it to our testee-thread’s pool’s work queue
  25. - Properly test `Thread->work()` by adding a file-static variable, setting it in a native `routine` and adding
  26. it to our testee-thread’s pool’s work queue
  27. - Properly test `Thread->current()` by wrapping a call to it into a native `routine` and
  28. adding it to our testee-thread’s pool’s work queue
  29.  
  30. ✓ Figure out how to properly namespace *types*. Structs are safe, but…
  31. - Internalize `Paws.h` includes
  32.  
  33. - Cest ‘Cets’
  34. - Store `ASSERT()` arguments in a string, if it fails
  35. ✓ normalize line returns between namespaced functions and struct methods
  36. ✓ replace `LL` namespace with `ll` where appropriate in the tests
  37. ✓ move the `ll_size` typedef into ll.h
  38. ✓ use `#if defined()` instead of `#ifdef`, and `#if !defined()` instead of `#ifndef`
  39. ✓ collapse `ll a_ll;\na_ll = …` into one statement
  40. ✓ re-indent preprocessor statements to align to tab stops
  41. - Replace /*-*/ with // where sensible
  42.  
  43. - ERROR! HANDLING!
  44.  
  45. ✓ Cest-out all existing code
  46. - basic numeric methods
  47. ✓ `infrastructure string` impl
  48. - memory management
  49. - routines
  50. - Some sort of remove function on `ll`s and `list`s
  51. ✓ Get rid of `ll_ssize` and negative indices entirely… *always* use unsigned indices, and provide a separate
  52. function for counting from the end
  53.  
  54. ✓ separate into various files
  55. ✓ make `thing` a struct with a pointer-union, so we can tell what is being stored (a ‘tagged union’)
  56. ✓ make ll a doubly-linked list
  57. ✓ change `e`, it’s a stupid name
  58. ✓ fix bus error with new `thing` struct
  59. - move `run` somewhere persistent
  60. - add an alias for `gdb`
  61. - use clang overloading
  62. ✓ do we need stdlib?
  63. ✓ add a useless-header warning to Types.h
  64. ✓ remove useless include-guards in .c files
  65. ✓ make `thing`s const
  66. ✓ get rid of the unnecessary ‘_methods’ in struct’s tags
  67.  
  68. - look into using an `enum` as the return value of `main()`, for error handling.
  69. - look into `__attribute__((nonnull))`
  70.  
  71. - How do I link an `execution` to the related `routine`?
  72.  
  73. ✓ Move all datatypes into a common subdir
  74. ✗ Remove `Core.h`
  75. ✗ Move `EXTERNALIZE` def into a more central location (Paws.h?)
  76. ✓ Move forward declarations of non-datatypes into their respective types
  77. ✓ Move `ast.*` in with `routine`
  78. ✓ Move `ll.*` in with `list`
  79. ✓ Remove all faux-‘inheritance’
  80. ✓ Simplify the `thing` mess
  81. ? Use casts instead of `thing`s where possible (almost certainly only use `thing`s as return values of `list`
  82. functions)
  83. ? Provide `DEFINE`s to make `a_thing.pointer.list` into `a_thing.list`
  84. - Provide `AS_LIST()`, `AS_ROUTINE()` etc macros to use on `thing`s
  85. ✓ Fix back to indented `E()`
  86. ✓ Re-hardwrap everything at 113 columns
  87. - Figure out a way to use `constructor`s again, instead of chaining registrations together
  88.  
  89. ✓ RE-ASSIGN HEADER INCLUDES!!!
  90.  
  91. - Indirect most calls through the libspace lookup chain
  92. - Lookups
  93. - `assignation`
  94. - `tuple`?
  95. - Synchronous, native routines
  96. - Native routines
  97. - Synchronous executions
  98.  
  99. ✗ Move pointer marker in Types.h to be right-aligned
  100. - Make root-level routine a `lobby`
  101. - Create `allocate` and `liberate` methods for each data type
  102. ✗ Remove the unnecessary `struct Paws extern Paws;` and add `extern Paws;` to the end of the original struct
  103. declaration. Do the same for all the other classes that do similar.
  104. - Externalize all function names
  105. - Should I be using `realloc()`?
  106. - Should probably replace `foo--`s with `--foo`s.
  107. - So much documentation left to do…
  108.  
  109. - why are there two naughties created
  110. immediately?
  111. - why is `routine._get(1)` undefined?
  112.  
  113.  
  114. - list return value on failed gets/lookups
  115. - undeclared object (do we need undefined
  116. object interp-side?)
  117. - implement a `name` routine, and `namer`
  118. relationship, for debugging
  119.  
  120.  
  121. - replace errors with functions that
  122. create errors, so we can get backtraces
  123.  
  124.  
  125. - make most of the native functions
  126. friendly to being stored on routine
  127. objects, and then expose them to
  128. libspace
  129. - ensure we use lookup’d libspace routine
  130. calls instead of function calls where
  131. possible, to allow for more overriding
  132. - go through and make style more
  133. consistent
  134. - make Error strings on the next line, and
  135. longer
  136. - change `list.length()` so we can make
  137. `string.length()`
  138. - enclosing scopes
  139. - libspace `beget`
  140. - remove support for
  141. `definition.beget({key:value})`, since
  142. it doesn’t work
  143. - do we need a third (fourth?) element in
  144. definitions, for metadata? why not just
  145. store it on the naughty?
  146. - what about ‘directionality’ instead of
  147. push/pop/shift/unshift on lists? Treat
  148. them as *either* FILO or LILO, and have
  149. only two methods… so lists are *either*
  150. a stack or a queue, not both at once.
  151. Would be good for APIs…
  152. - If you *really* need to work with the
  153. wrong end, you could `apply` the
  154. routine from the opposing prototype…
  155. - sexy syntax for applying. `foo bar`
  156. calls your *own* `bar`, but what about
  157. `baz [qux] apply(foo)` or whatever?
  158. That’s really ugly for applying somebody
  159. else’s `qux` to yourself
  160.  
  161.  
  162. - interpreter loop!!!!!!
  163.  
  164.  
  165. - Move lenses into their own files
  166. - Date lens
  167. - RegEx lens
  168. - Function lens
  169. - Error lens
  170.  
  171. - Do not continue codes during indentation
  172. - Clean up API (`unapplyCodes() and such
  173. should *not* be public!`)
  174. - Can we D.R.Y. the CSI, codes.join, SGR
  175. sequence out into the `[un]applyCodes()`
  176. functions?
  177.  
  178. ✓ Hilight escape codes in strights in a
  179. ‘hi’ variant
  180. ✓ Support undefined, null
  181. ✓ Treat natives differently from wrapper
  182. objects; support separate lenses for the
  183. two
  184. ✓ Perhaps try a `typeof` before climbing
  185. into prototypes and properties? Then
  186. we could have an 'undefined',
  187. 'string', 'number', etc
  188.  
  189. ✓ stack ‘seen’ objects, recognize
  190. recursion
  191. - track length, intelligently decide
  192. between printing sub-elements on
  193. newlines and printing them inline
  194. - how do we expose this functionality to
  195. lenses?
  196. - combine *really* short elements onto
  197. one line
  198. - can we `diff` objects? retain old state,
  199. compare to new state. show changes?
  200.  
  201. ✓ how do I recursively peer into objects,
  202. yet preform different actions on them?
  203. i.e. if we start with an ANSI terminal
  204. printing, each recursive object should
  205. print as ANSI with Yarn… but if we start
  206. with a toString-ing, each recursive
  207. object should print *without* ANSI…
  208. ✓ some sort of way to pass a ‘recurse()’
  209. or ‘sub()’ function to the lenses,
  210. that we can then exchange out based on
  211. what we actually want to *do*?
  212. ✓ but then how do the lenses know
  213. whether to use ANSI or not, etc?
  214. ✓ lenses return yarns or strings,
  215. yarns will be styled later on
  216. ✓ use names instead of styles? or names
  217. as an alternative to styles?
  218.  
  219. - a ‘style’ for adding indentation, i.e.
  220. for printing `Function` objects, or Paws
  221. ASTs… could define a style of four extra
  222. spaces
  223. - can we print `Function` objects more
  224. intelligently? Less than printing the
  225. entire sourcecode, more than printing
  226. the word ‘function.’ Perhaps we can suss
  227. out arguments and the return value.
  228.  
  229.  
  230.  
  231. 1 ¦ operator “operand*operand”
  232. 2 ¦ replace “foo bar” “2*2”
  233. 3 something { what (foo bar baz) * 8 }
  234.  
  235.  
  236.  
  237.  
  238. 2 * (2) ⇥ 1
  239. 2 ¦ replace “foo bar” “^ ^ ^^^”
  240. what (foo bar baz) * (8) ⇥ 1
  241. 3 something { ^^^^ ^^^^^^^^^^^^^ ^ ^^^ }
  242.  
  243.  
  244.  
  245.  
  246. 2 * (2) ⇥ 1
  247. what (^ ^ ^^^ baz) * (8) ⇥ 2
  248. 3 something { ^^^^ ^^^^^^^^^^^^^ ^ ^^^ }
  249.  
  250. - `.foo(a_list)` called
  251. - needs a value from `a_list`: calls `.lookup(a_list, a_string)`
  252. - needs lookup routine, calls `.metalookup(a_list)`
  253. - `.at()` the `0, 1, 2`th entry of `a_list` to get `a_metalookup_routine`
  254. - `.synchronous_execute(a_metalookup_routine)`
  255. - Create `a_result`, and wrap in a pointer to a location to which the
  256. result value should be written (LOCATION)
  257. - Create `an_execution` from `a_metalookup_routine`
  258. - Set `an_execution`’s arguments to `a_string`, and caller to `a_result`
  259. - `.execute(an_execution)`
  260. - Check if `an_execution->routine` is native or not
  261. - If native, `an_execution->routine->native(an_execution)`
  262. ~
  263. - native metalookup implementation does its stuff, acquires `a_lookup_routine`
  264. - native impl calls `Routine.execute(an_execution->result)`
  265. ~
  266.  
  267.  
  268. Notes:
  269. ======
  270. - The
  271. - Character position data never *exists* for intermediate ASTs: all character
  272. positions refer to the position in the **original document**. This means
  273. multiple nodes might point at the same character positions in the
  274. original document (this is by design; for instance, multiple instantiations
  275. the same preprocessor command.)
  276.  
  277.  
  278. More Paws
  279. =========
  280.  
  281. ### Big TODO
  282. - Unicode and semanticity
  283. - Old-school mathematical operators instead of faux ASCII programming ones
  284. - Infix operators
  285. - Nothingness (undeclared, undefined, and null)
  286. - Federationist compilation
  287. - Co-operative, networked compilation-unit discovery
  288. - Asynchronicity
  289.  
  290. ### Little TODO
  291. - `is` keymethod (`foo is bar` calls `foo bar?`, tries to return booly)
  292. - boolyness (things know how to make themselves booly)
  293. - Whitespace (U+0020 ‘SPACE’ or U+000A ‘LINE FEED’, no Windows support, why?)
  294.  
  295. Scope
  296. -----
  297. /scope/
  298. : a /namespace/, connected to knowledge of the enclosing /scope/.
  299. /namespace/
  300. : a list of associations, of /name/s to objects.
  301. /name/
  302. : any literal series of non-/whitespace/ characters
  303.  
  304. ### `scope` function
  305. A new /scope/ is explicitly introduced with the /`scope`/ function.
  306. /statement/s inside the /block/ attached to that function dereference /name/s
  307. using a new /namespace/ attached directly to it.
  308.  
  309. /block/
  310. : any series of /procedural/ /statement/s
  311. /statement/
  312. : a
  313.  
  314. scope
  315. a ↼ 1, b ↼
  316. scope
  317. a ↼ 2, b ↼ 2, c ↼ 2
  318. a = 2 & b = 2 & c = 2
  319. a = 1 & b is undefined & c is undeclared
  320.  
  321. ### Lookups
  322. How we run through `foo ↼ 123`
  323.  
  324. - `foo` is dereferenced in `locals namespace`; no such name exists, so the
  325. `namespace` returns an `undefined`, with `the.undefined scope` attached to
  326. `locals`, and `the.undefined name` attached to the missing name
  327. - `↼` is dereferenced in `the.undefined namespace`; it dereferences to a
  328. function
  329. - `the.undefined ↼ infix?` is `true`, so we look ahead and deal with `123`
  330. - `123` is a literal, so we don’t have to do anything with it
  331. - We call `the.undefined ↼(123)`
  332. - The implementation of `↼` does something akin to
  333. `my scope __set(my name, 123)`
  334.  
  335. - preform high-level processing to break the document down into routines,
  336. expressions, and preprocessing directives
  337.  
  338. - process the operators in each expression
  339.  
  340.  
  341. ¦ operator “value ? routine : routine” (left, medium) “infrastructure ?:”
  342. ¦ operator “value−value” (left, medium)
  343. ¦ operator “value×value” (left, medium)
  344.  
  345. 2 − 3 × 2 × 2 − 5
  346. 2 − (3 × 2 × 2) − 5
  347. 2 − (8 × (2)) − (5)
  348.  
  349. ¦ operator “value↑value” (right, medium)
  350. 5 ↑ 4 ↑ 3 ↑ 2
  351. 5 ↑ (4 ↑ (3 ↑ 2))
  352. 5 ↑ (4 ↑ (3 ↑ (2)))
  353.  
  354. ¦ operator “value ? routine : routine” (right, low) “infrastructure ?:”
  355. ¦ operator “value:value” (right, high)
  356. something ? then : else.maybe ? foo : bar
  357. something ? then : (else.maybe ? foo : bar)
  358.  
  359.  
  360. something ? then.maybe ? foo : bar : else
  361.  
  362. something ? foo : bar : else
  363.  
  364. “Senseless example, because `(bar: baz)` will always evaluate as true… but
  365. here for testing purposes nonetheless.”;
  366. foo ? bar : baz ? qux : quux : corge : grault
  367. foo ? ((bar: baz) ? (qux: quux) : corge) : grault
  368.  
  369. - Multiple frameworks in Paws.o:
  370. - Object system: Provides data types and ‘object’ APIs; handles internal
  371. interactions between items in the ‘world,’ such as lookups
  372. - Interpreter: Handles ‘worlds,’ specifically, ‘interpretation units.’
  373. Comprises the garbage collection system, IU federation/
  374. networking components, the routine-threading model, and (of
  375. course) the actual procedural AST interpreter.
  376. - Parser: Comprises the lexer and parser, and provides APIs to access and
  377. modify the AST. Handles conversion of a I/O stream to a token
  378. stream, and subsequently conversion of that token stream to an
  379. AST. Must provide intermediate stages for the final portion…
  380. - Preprocessor: Responsible for turning a Paws document (with operators,
  381. macros, constants, and such) into a µPaws document (sans
  382. operators, consisting entirely of routine literals and word
  383. lists)
  384.  
  385. Provided binaries:
  386. - `paws`, a combination wrapper for all of the above stages: takes a full-on
  387. Paws source file, preprocesses it, and interprets the result.
  388. - `ppaws` (the ‘Preprocessor for Paws’), a direct interface to the
  389. preprocessor and parser portions. Takes a full-on Paws source file, and
  390. spits out a valid µPaws document, with all operators and macros handled out
  391. - `upaws`, the C interpreter itself, a direct interface to the parser,
  392. interpreter, and object system. Expects a µPaws document; will not invoke
  393. the preprocessor, and thus will not properly handle operators or macros.
  394.  
  395. Can expect in the future:
  396. - `lassie`, a REPL-on-steroids… more accurately, an interactive interpreter
  397. tied to an object system interrogator
  398. - `cpaws`, a bytecode-compiler to Paws objects
  399. - `vpaws`, a bytecode-VM for Paws objects
  400.  
  401. Preprocessor details:
  402. - Since there are no comments, nor illegal characters in names, we have to use
  403. valid names as our preprocessor directives. This has the side effect of
  404. making our un-preprocessed Paws files valid µPaws files… they simply won’t
  405. execute as expected (given that there will probably be a lot of weird,
  406. unexpected lookups.)
  407. - Most likely, use ‘magic strings,’ since that’s how comments normally work.
  408. Again, a side effect of making the preprocessor directives accessible from
  409. the processed µPaws, if a library author really wants to grab them for some
  410. reason.
  411.  
  412. Macro example:
  413.  
  414. “=macro ‘FOO BAR’ baz”;
  415.  
  416. “ The following will become `something baz something.else`: ”;
  417. something FOO BAR something.else
  418.  
  419. Operators will be defined via preprocessor directives in this format:
  420.  
  421. `=operator ‘«identifier»’ «arity» [«associativity»] [«priority»] [«expansion»]`
  422.  
  423. - «identifier» is the word or sentence of source code that will be treated as
  424. an operator
  425. - «arity» is the number of arguments the operator takes (can be a numeral, or
  426. a word following the ‘unary,’ ‘binary,’ ‘ternary’ pattern)
  427. - «associativity» is the direction in which the preprocessor will search for
  428. words to attach the operator to (can be either ‘left,’ ‘right,’ or ‘none’;
  429. defaults to ‘left’)
  430. - «priority» determines how the operator is handled in proximity to other
  431. operators; can be a positive or negative numeric value, with higher (more
  432. numerically positive) values being processed earlier (more ‘inner’). Can be
  433. a numeral; one of ‘low,’ ‘medium,’ ‘high,’ (which correspond to -100, 0,
  434. and +100, respectively); or one of the previous extremes with a number of
  435. instances of the word ‘very,’ which indicates an additional power of ten
  436. (i.e. ‘very very high’ is equivalent to +100e2, or +10,000)
  437. - «expansion», if present, determines an alternative expression that will be
  438. used to resolve the operator
  439.  
  440. After order/grouping is determined, the preprocessor turns each operator and
  441. its relative expressions into a single ‘indirected lookup’ (usually, actually,
  442. a routine call… but not necessarily) expression, depending upon whether an
  443. expansion was defined for the operator or not.
  444.  
  445. If no «expression» was defined for an operator, then an operator-lookup is
  446. preformed on the first argument to the operator (which is the ‘first’ argument
  447. is determined by the «associativity»); the rest of the arguments are passed to
  448. the routine call serially: if `foo` has no «expression» and is left-
  449. associative, then `bar foo baz` becomes `bar foo (baz)`, i.e. a call to
  450. `bar`’s `foo` routine, with `baz` as an argument. This means that unary
  451. operators become argument-less function calls: right-«associativity» unary-
  452. «arity» `√` turns `√something` into `something √ ()`.
  453.  
  454. If an «expression» *is* defined, then it is used in place of that lookup. For
  455. instance, if our `foo` operator *did* define an «expression», let’s say
  456. `a b c`, then our `bar foo baz` would be processed into `a b c (~(bar) ,(baz))`
  457.  
  458. Operator example:
  459.  
  460. “=operator ‘+’ binary left medium”;
  461. “=operator ‘√’ unary right high mathematics √”;
  462.  
  463. “ The following will become `mathematics √ (foo) + (bar)`: ”;
  464. √foo + bar
  465.  
  466. ------------------------------------------------------------------------------
  467.  
  468. - multiple preprocessor runs
  469. - maintain source information for each preprocessor run-through, and final
  470. interpretation stage
  471. - file, line number
  472. - line index of first character of literal
  473. - nesting level (within routine literals / expressions)
  474. - file/line number/index of each routine/expression? how?
  475.  
  476. Preprocessor declaration initiators:
  477. ¦ operator
  478. ::operator (for ASCII compat)
  479.  
  480. So, preprocessor runs through; every time it sees a processing instruction, it
  481. stores that instruction along with the place it found the instruction.
  482.  
  483. ¦ operator “∫”, “(”, “)” (ternary, postfix, left, medium) “mathematics ∫”
  484.  
  485. “Becomes `mathematics ∫ (~ (4) , (10) , (foo bar))`:”
  486. 4∫10 (foo bar)
  487.  
  488. ¦ operator “?”, “:” (ternary, postfix, left, medium, routine) “infrastructure ?:”
  489. ¦ operator “value ? routine : routine” (left, medium) “infrastructure ?:”
  490.  
  491. “Becomes `infrastructure ?: (~ {@(foo is.awesome)} , {@(then do)} , {@(else do)})`:”
  492. foo is.awesome ? then do : else do
  493.  
  494. (Can we somehow declare *individual arguments* that should be routines instead
  495. of values? Turning *every argument* into a routine literal is a bit meh…)
  496.  
  497.  
  498. what about routines ‘falling forward?’ We want execution to always proceed in
  499. a ‘forward’ direction, correct… no return values, means no returning, means no
  500. falling ‘backwards’ to your call*er*. But blocking calls with a sync
  501. abstraction pretty much do that ANYWAY, which breaks our own rules…
  502.  
  503. … so, instead, we could *completely kill* the calling routine. We already need
  504. a ‘called routine’ object, that stores the locals for a given execution,
  505. right? We could also, somehow, store the execution-state (that is, *where* in
  506. the execution it is); then, we don’t even *need* to maintain old interpreters!
  507. We just pass the caller ITSELF to the callee AS A RESULT-ROUTINE! Then, when
  508. the called routine has a value to hand back, it calls-forward to this
  509. partially-executed routine, with the result.
  510.  
  511. The arguments to a partially-executed routine *wouldn’t* be stored in `@` or
  512. whatever; instead, they would be stored as a result-value of the position
  513. where the callee was called.
  514.  
  515. cloudhead says we can ‘unroll the stack…’ I think I understand…
  516.  
  517. also, new possible semantics, libside: a routine can ‘result’ (continue its
  518. caller) multiple times, with different ‘results.’ Imagine a for-each construct
  519. that simply results multiple times! Compare:
  520.  
  521. routine {
  522. (1, 1, 2, 3, 5, 8, 13, 21) for.each { I/O standard out write(@) }
  523. } execute
  524.  
  525. routine {
  526. I/O standard out write((1, 1, 2, 3, 5, 8, 13, 21) each)
  527. } execute
  528.  
  529.  
  530. - Federated IUs will have to, somehow, ‘share’ lookups?
  531. - Perhaps use the same system as, uh, everything else: failed lookups
  532. fall-through to the ‘parent’ environment.
  533. - What about overriding/assigning stuff? Then again, inheritance has the
  534. same ‘problem’. So maybe it isn’t really a problem.
  535. - Lists may have a GULID (Globally Unique List-ID) attached to them. When
  536. interpretation units federate, they may ‘decide’ (?) that two objects are,
  537. in fact, the ‘same object’ for the purposes of execution.
  538.  
  539. So… ‘remote’ objects will simply have another `lookup()` semantic: before
  540. following *any other* lookup procedure, they will preform a lookup on their
  541. ‘local proxy’ (which only remote objects have). This local proxy overrides
  542. `get()` and `set()` such that those are passed through a tunnel to the
  543. ‘owning’ IU.
  544.  
  545. This should, actually, handle *any* situation where multiple IUs come into
  546. contact. The only thing that changes is how the tunnel operates:
  547.  
  548. - ‘snug’ IUs: same interpreter process (i.e. included files and packages)
  549. - ‘near’ IUs: separate, but nearby, interpreter processes (same machine, or a
  550. machine on a very, very fast local subnet, i.e. fast-LAN… such
  551. that it can be treated as the same machine)
  552. - ‘far’ IUs: separate, and far away, interpreter processes (different
  553. machine, different network, possibly different interpreter… i.e.
  554. server IU on Paws.o, and client IU in a browser on Paws.js)
  555.  
  556. These tunnels cover all sorts of IU-interaction scenarios:
  557.  
  558. - localized sub-interpretation-units, such as an equivalent to `eval()`
  559. - ‘file’ interpretation units… such as an equivalent to `require()` or a
  560. packaging system
  561. - multiple ‘server’ processes, handling some sort of distributed task
  562. - client-server IU communication
  563.  
  564.  
  565. -foo
  566. foo+bar
  567.  
  568. |foo|
  569. foo a bar b
  570. foo?bar:baz
  571.  
  572. /foo/bar/
  573. foo a bar b baz c
  574.  
  575. - ‘look up’ the operator *on* what?
  576. - what if what you’re looking it up on
  577. changes at runtime? can’t look it up on
  578. something new… or, can, but it may not
  579. be an operator there
  580.  
  581. Okay, once it’s a parse-tree static…
  582.  
  583. foo ? bar : baz
  584.  
  585. [operator, ['?', ':'],
  586. [identifier, 'foo'],
  587. [identifier, 'bar'],
  588. [identifier, 'baz']]
  589.  
  590. ? :
  591. ↙ ↓ ↘
  592. foo bar baz
  593.  
  594. … it would be looked up as `(‘?’,‘:’)`
  595. on `foo`, regardless of the content of
  596. `foo`.
  597.  
  598.  
  599. Paws
  600. ====
  601. Take all the good bits of JavaScript. Leave out the ideological dependence on
  602. the DOM, leave out the horrible insecurities regarding the prototyping system,
  603. leave out the stupid psuedo–types–that–pretend–to–be–objects.
  604.  
  605. Now mix in a little Ruby: C extensions (speed when we need it, and the whole
  606. ridiculous pile of C libraries at our disposal), intelligent handling of
  607. nested scope and `self`, absolutely every thing in the system behaves properly
  608. as is expected of a true thing (even if it’s implemented as a non–thing on the
  609. backend, like Numeric).
  610.  
  611. Finally, garnish it with a few oddities from around the world: Io’s lobby
  612. instead of any sort of global scope, Node.js’s obsession with eventual
  613. programming and refusal to block for *anything*…
  614.  
  615. Wrap it up in a beautiful hybrid syntax, a bastardization of JavaScript’s
  616. object notation, Io’s whitespace–based expressions, Python’s meaningful
  617. indentation, and Ruby’s raw sex appeal.
  618.  
  619. Welcome to Paws.
  620.  
  621. Look & feel
  622. -----------
  623. Paws likes to feel pretty. Everybody knows that negative space is pretty.
  624.  
  625. a.thing = {widget: "foobar", whatsit: 2}
  626. a.thing widget = "metasyntactic variable"
  627.  
  628. a.thing > another.thing
  629. print( another.thing widget # metasyntactic variable
  630.  
  631. Unlike, well, every other language, we open up names to all sorts of stuff:
  632. periods, apostrophes, even Unicode characters. Better yet, slots aren’t
  633. restricted in the very few ways that names are; you can name a slot after
  634. *any* string (even the empty string, `''`!) Of course, you can only directly
  635. reference a slot via the space operator if that
  636.  
  637. Prototypal inheritance
  638. ----------------------
  639. A child of a thing is just an empty thing whose `isa` field points at the thing
  640. it is a copy of. Missing slots are proxied to the parent thing.
  641.  
  642. foo = {} # <foo>
  643. foo isa # <thing>
  644. foo thing = 123 # 123
  645.  
  646. foo > bar # <bar>
  647. bar isa # <foo>
  648. bar thing # 123
  649. bar thing = 456 # 456
  650.  
  651. bar > gaz # <gaz>
  652. gaz isa # <bar>
  653. gaz thing # 456
  654.  
  655. bar delete thing
  656. gaz thing # 123
  657.  
  658.  
  659. - Details on references
  660. - Syntax for resulting & space-operator-wait() (square brackets?)
  661. - `foo bar baz qux quux corge grault`, if `qux()` calls three callbacks, how
  662. do we say we want
  663. - foo(bar: routine, gaz~ routine)[gaz, bar]
  664.  
  665. “quux gets anything passed to @last() by qux”
  666. foo bar baz qux quux corge grault
  667.  
  668. “quux gets anything passed to @result() by qux”
  669. foo bar baz qux(arg, result~ routine, foo: routine) quux corge grault
  670.  
  671. “quux gets anything passed to @result() by qux”
  672. foo bar baz qux(result.one~, result.two~) quux corge graulta
  673.  
  674.  
  675.  
  676. Thoughts
  677. ========
  678. - a ‘suzerain thread’ is launched by the OS when you run the interpreter. A thread becomes the suzerain by
  679. calling the initial interpreter-initialization function, whatever that will be.
  680. - The suzerain will be frozen once it spins off the root routine-interpreter thread; it will only be unfrozen
  681. when a process-relevant task has to be preformed (exiting, or handling signals maybe? dunno).
  682. - Problematic: Recursive ownership. If the `owner` is a manifold-singleton, like everything else in Paws… then
  683. it’s not enough to cause exclusive execution for `atomic` `routine`s against the *`owner`*… because said owner
  684. might simply be a call-literal `list`, implying *multiple* `owner`s. In addition, even if there is a single
  685. `owner`… we have to worry about `routine`s that try to access ‘child objects’ of that `owner` that are at risk
  686. for mutation! Compound the two issues, and you have to worry about the entire sector of the object-space
  687. referenced by a `routine`’s `owner`.
  688. - Possible: Climb entire object space below a `routine`’s `owner`, and exclude from execution any `routine`
  689. whose `owner` conflicts at any point. Ew.
  690. - Possible: declare, libside, which `definition`s you are ‘responsible’ for (it’s like `owner`ship… for things
  691. instead of `routine`s: if you are `responsible` for one of your children, then it is also atomically locked
  692. against when you are atomically locked against)
  693.  
  694.  
  695. take a metapointer (hah, fuck you, Zhivago) to an AST node; then update the reference as we iterate
  696.  
  697. that way, we can be `execution`-agnostic in all of `routine`’s code, and then leave it up to `execution`’s code
  698. to handle relationships between the routine and the execution
  699.  
  700. I don’t like that we have a *specific type of data* to hold A) a list of stuff, including arguments and caller,
  701. and B) a pointer into the AST… but then we don’t utilize that as an argument when we need exactly those two
  702. things. On the other hand, we can’t exactly properly *construct* one of those types using a `routine` without
  703. getting ridiculously recursive…
  704.  
  705. so, *either*…
  706. - I can call a constructor-type routine after allocating, which makes it more ‘libspace friendly’, *or*
  707. - pass a semantic `execution` object to `Routine.interpret()`
  708.  
  709. - … what if I put it in `Execution.interpret()`? But that seems so fugly/unsemantic *too*…
  710.  
  711.  
  712. Things an `execution` stores:
  713. - interpretation state, i.e. pointer into the AST representing where to (re)start interpretation
  714. - the (list of) argument(s) passed in
  715. - the ‘instantiated’ locals-scope of the routine (falls upwards to the closed-over scopes of the execution in
  716. which the routine was created, etc)
  717. - the thing the routine was ‘called on’ (you know, `this`)
  718.  
  719. THINGS TO CONSIDER:
  720. - how the hell do I create a many-to-one relationship in a function call? How do you have *multiple* functions as
  721. your `caller`?
  722. - how do you have multiple `this`es? or rather, I suppose, `these`? Perhaps we can allow a lookup on a `call`
  723. literal to simultaneously fall through to all of its children, and then … execute the result(s?) with multiple
  724. items in `these`?
  725. - What about executing an `execution` against multiple routines? How do we store the execution status (node
  726. pointer) and each
  727. - In the spirit of ‘single-multiple everything,’ what about multiple scopes? Perhaps, treat a lookup against
  728. multiple scopes just like any multiple-lookup: pass `these` as the scopes that metalookup identically
  729.  
  730. - There’s a lot of places where we’re wrapping multiple things up in one thing, and trying to make it easy to be
  731. agnostic about whether that thing is a thing, or multiple things. Should we have a centralized concept to
  732. handle this (really common) situation, other than just the `call` literal?
  733.  
  734. - Penetrating lookups; several things (`definition`s, call-literals, `ghost`s and `fork`s) are intended to be
  735. “transparent”: what about having them be transparent on the request-side, not the receiver-side? That is,
  736. lookups ‘fall through’ unless A) they are marked to not penetrate that specific kind of thing, or B) there is a
  737. “backstop” routine on that kind of thing (a lá `definition ↼()`).
  738.  
  739. - Can we abstract first-class `fork`s out to being *every* `list`? That sort of turns every object into an “event
  740. emitter” a lá Node.js: that is, every time an element is added to a list, the places that `fork()`ed against
  741. that list, get immediately branched with that new element. It’s threaded eventing, on every object in the
  742. system.
  743. - So, how would that tie into `routine`s, resulting, `execution`s, `ghost`s? Essentially, at that point, every
  744. object in the system might as well be a `ghost`: instead of `routine`s returning anything special, we can
  745. simply grab an empty list from them, that `result`s will be placed into as they become available.
  746.  
  747.  
  748. - Why are numbers globally unique?
  749. - Why store numbers as strings?
  750. - How do we normalize numbers into a single string representation, to make them globally unique (i.e. ‘1234567’
  751. and ‘1.234567E6’ should obviously normalize into the same `numeric`)?
  752.  
  753.  
  754. Problems
  755. ========
  756. - There’s some confusion around the interaction of the asynchronicity (`execution`s) and concurrency (ownership)
  757. systems. Does an atomic `routine`, one that needs exclusive write-access to a thing for a while, retain
  758. exclusive access to that thing once it’s blocked? (remember, blocking means it’s gone, in our system).
  759. - If so, isn’t there a possibility of it being access-locked forever? If a blocking call goes out, destroying
  760. the caller, and the caller has locked some thing… and then the caller is never called back to, then access
  761. will never be released
  762. - If not, then while the caller is blocked (gone), other things might access the locked thing, completely
  763. defeating the purpose of atomicity and ownership (because the thing you’re prefomring multiple,
  764. interdependant actions on, may be introspected, or even modified, before you’re through… specifically,
  765. during the call out)
  766. - This is even a problem with non-blocking routines; specifically, if you exercise an execution situated
  767. halfway through a routine, things may have modified/accessed half-complete data you owned
  768.  
  769. - any staged or queued `execution` implies a state of lock based on ownership
  770. - if a staged `execution` is unstaged for any reason *other* than having reached the end of the `routine` it’s
  771. being exercised against, its ownership-mask is perpetuated
  772. - a perpetuated mask has the exact same effect as a staged routine’s mask; that is to say that a list of
  773. perpetuated masks is stored somewhere, and checked against in the same way as the staged routines’ masks when
  774. new routines are to be staged
  775. - when that unstaged `execution` is exercised *or* forked into a new `execution`, the mask is
  776. - uh, instead… we seperate the ‘exercise stage’ and ‘lock stage’: lock stage is checked before an execution is
  777. staged? however, once staged, it is staged to *both*. Unstaging in the process of execution only removes it
  778. from the exercise stage; remains on lock stage, which in effect locks all the resources the execution *was*
  779. utilizing as if the execution was still in play
  780. - what about *forking* executions?
  781. - could lock-stage all forks of a lock-staged execution
  782. - conflict eachother?
  783. - then, when execution is exercised again at a later point, place it back on the exercise queue… and ensure it
  784. won’t conflict with *itself*
  785. - wait: executions should expire once they realize the entire routine, anyway. calling them would do nothing once
  786. their pointers point to the end of the AST9
  787. - okay, one more stab…
  788. - screw applying an execution to multiple routines, it complicates things too much!
  789. - first off, three “periods of life” of an execution:
  790. 1. pre-staging (has never been staged; points to root scope-node of the routine)
  791. 2. post-staging (is staged or has previously been staged; points to somewhere within the `routine`)
  792. 3. invalidated (has completed execution of the `routine`, or has been manually invalidated; points to NULL)
  793. - so…
  794. A. once an execution has been staged… until it is completed (invalidated), it must remain in the locktables.
  795. B. forking a staged or previously-staged execution (that is, any execution in the locktables) must also enter
  796. the fork-execution into the locktables
  797. C. forking is meaningless in the context of a pre-staging execution (‘forking’ would just be creating a new
  798. execution for the same routine) or invalidated execution (forks would also be invalid), so…
  799. Z. we simply need to put every forked execution into the locktables, and remove them when they individually
  800. realize
  801. - This all mixes very badly with atomicity: essentially, it boils down to “storing executions for long periods of
  802. time also locks resources for long periods of time, preventing atomic access for long periods of time”: you
  803. won’t be able to *atomically* modify resources which are locked by momios (executions in reefersleep :D)
  804. - problem isn’t really *difficult* to solve… you simply either avoid locking data with routines which are
  805. likely to be forked in complex and time-spanning ways, or avoid passing around your execution when you *do*
  806. need to atomically modify data.
  807. - If necessary, you can wrap the atomically-modifying bits of your routine in an atomic subroutine, before or
  808. after the execution-point
  809. - I have yet to think of a situation where atomic operation’s *and* momio’s code have to be interleaved… but
  810. such situations *might* exist. I’m not sure how to deal with them.
  811.  
  812. so, more …
  813. Problems
  814. ========
  815. - fuck synch routines
  816. - I mean seriously. that’s just causing endless problems with, well, everything. If we can’t store the C-stack
  817. behind a given stage’s *actual pthread*… which we certainly can’t easily do… then there’s no way to provide
  818. an `execution`, for a synch-routine, that can later be exercised again! If you unstaged (ceased) the
  819. synch execution, then you’d never be able to re-instate the C-stack involving the calling execution below
  820. the synch execution… gah! And then you’d never be able to, you know, FUCKING RETURN to the caller, which was
  821. the point of synch routines. And we can’t just dictate that you can’t get a later-exercisable `execution`
  822. for synch-routines, because that’s the entire spheil behind `ghost`s, right? Calling `ramify()` inside the
  823. `lookup()` routine?
  824. - calling complex/asynchronous shit from native routines
  825. - we *gotta* have some sort of convenience toolset for calling routines from C-side, right? But, without synch-
  826. routine support, how do we *do* that? Like, lookups. How the fuck do we perform a basic lookup… saying, for
  827. instance, we wanted to provide an interpreter hook into `get()`: we’d need to provide a native `get()`, but
  828. then instead of directly *calling* that, we need to preform a lookup for `get` and then call that the full-on
  829. libside-friendly way, so that `get` can be overridden. In that situation, how do we *perform* that damn
  830. lookup for `get`?
  831. - okay, ever since I introduced ghosts/futures/wtfever, I’ve been confused as to which way resulting works:
  832. - old-world call-the-execution-to-resume-realization, wherein the ISV of the originating call becomes the
  833. argument to `exercise()`
  834. - new-world add-results-to-a-`result`-ghost-as-you-realize, where the ISV of the originating call is the
  835. `ghost` that will be filled with results
  836. - the old-world way is still useful; obviously, that’s how `ramify()` and similar have to operate
  837. - the new-world way, to some extent, can be… implemented? in terms of the old-world way?
  838. - could we dictate that *all* executions work old-world… and then have a libspace routine that *wraps* stuff
  839. in the new-world way: that is, it `exercise()`s the caller before running your shit, with a new `ghost`…
  840. and then realizes *your* stuff, after having `exercise()`d the caller, with the `ghost`: at this point,
  841. from within your own stuff, you utilize some sort of convenience method, `result()`, to add stuff to the
  842. ghosts
  843. - this way, we wouldn’t need blocking routines: *all* routines are blocking, until you call the caller’s
  844. `execution`, which means you can implement non-blocking routines that return a ghost entirely in libspace:
  845.  
  846. non-blocking ↼ { this calling execution exercise(routine {
  847. owner result ↼ infrastructure ghost allocate()
  848. this calling execution exercise(owner result)
  849. owner exercise() }) }
  850.  
  851. then, from within the routine you wrap as `(a_routine)non-blocking()()` or sth., and the result will be
  852. something you can call and get a `ghost` from.
  853.  
  854. Getting rid of arguments
  855. ========================
  856. What about *completely getting rid of* arguments and owners to *routines*?
  857.  
  858. At the end of routine execution, there’s … nothing. No return value. That seems “out of balance” with the fact
  859. that at the *start* of routine execution, we have parameters…
  860.  
  861. … in addition, we originally had “multiple arguments and multiple returns” while actually only having a single
  862. argument and a single return value, and allowing each one to be a list. Now we no longer have returns, instead
  863. having results… and while each result is singular, with the possibility of having multiple elements added… there
  864. *are* multiple results throughout the function.
  865.  
  866. So, why don’t we sort of go full-on coroutine style, and make the only way to get parameters into the routine be
  867. via the executions? You could still get traditional “arguments” this way, by having the routine immedtiately call
  868. its caller (thus giving the caller a handle on an *execution*, which it can then give arguments) or something.
  869.  
  870.  
  871. HOW DO I CONSTRUCT?
  872. - have to allocate the underlying structure first
  873. - call a native routine that does libspace `list` configuration *as well as* `node` assignment
  874.  
  875. Other ideas:
  876. ------------
  877. Multi-use parser framework: break parsing down into stages, each stage can be a specific, restricted, ‘type’
  878. allowing for for more judicious processing. For instance, one stage might break down a Paws document’s routine-
  879. structure, while another might parse individual lines into subexpressions, and yet another might break
  880. subexpressions into words. Each stage would be given callbacks and calls into other stages8
  881.  
  882. - package installation for Node.js?
  883. - packages are just .tar.gz
  884. - separate systems for ÔinstallationâÕ (really, just sourcing of new packages from a sort of database, repository, or package list; downloading of said packages; and expanding them into a libraryPath) and dependency resolution, outside of the acquire system itself
  885. - perhaps use same system for the two of the above, so the installation process can preform recursive dependency installation as well
  886. - gemcutter for Node.js?
  887. - API?
  888. - S3?
  889.  
  890. - caliper (hosted metric_fu)
Add Comment
Please, Sign In to add comment