Skip to content

Latest commit

 

History

History
509 lines (350 loc) · 18.6 KB

README.md

File metadata and controls

509 lines (350 loc) · 18.6 KB

Icon "inclusion library"

Incorporate these files into Icon programs using the $include preprocessor macro:

  • This may be readily achieved by including this directory in your LPATH environment variable.
  • This may be require less preparation and updating than would translating to "ucode" and using the link directive.

development repo: https://chiselapp.com/user/eschen42/repository/aceincl

mirror and release repo: https://github.com/eschen42/aceincl

Contents

  • Testing program runt.icn and working examples

    • In the tests directory are "working examples" of how to use the files in this directory.
    • The runt.icn runs the test programs to validate their output.
  • fieldedDataFile.icn

    • Procedures to produce logical lines or fields from formatted data files.
  • fileDirIo.icn

    • Procedures to manipulate files, directores, and their paths.
  • iimage.icn

    • Procedures to transform data structures into includable Icon declarations and statements.
  • LiComboP.icn

    • Procedures to suspend lists combining sequences.
  • RecTable.icn

    • Procedures to produce/manipulate record-like tables.
  • rpn.icn

    • Procedures to embed RPN-based (Forth-like) interpreter into Icon programs; can also be run in REPL.
  • runningStats.icn

    • Support computing summary statistics for normally distributed data using "Welford's online algorithm".
  • selectRecordFromListByField.icn

    • Procedure to produce records from a list of records (or a list of tables), matching specified criteria.
  • vnom.icn

    • "Nominal vector", i.e., a list whose elements may be accessed by rank (index) or name (key).
    • This construct is supported by a Lua-inspired metatable.
  • wora.icn

    • Procedure to produce a value that can be read globally but can be reset only by the co-expression that set it it initially.
  • Legacy Source Code Control

Testing program runt.icn and working examples

Working examples, named test_*.icn, are in the tests directory:

  • test_*.std captures the corresponding test's expected output.
  • icon runt.icn tests will run the tests and compare the results to their expected output.
  • usage: icon runt.icn [--continue] [--verbose] [<zero or more dirs>]
    • By default, tests are located and run in the current working directory.
      • Otherwise, tests are located and run in the specified directory or directories.
    • Tests are not run unless an .icn file and a .std file share exactly the same name.
    • Use the --continue option to run all tests regardless of whether any fail.
    • Use the --verbose option to show both the expected output from the .std file and the actual output produced by the test program.

fieldedDataFile.icn

Procedures to produce logical lines or fields from formatted data files.

record FieldedData(lines, fields)

Produce record holding two co-expression factories:

  • lines === tabularLines | iniLines
  • fields === tabularFields | iniFields

procedure FieldedDataFactory(format, filePath) : FieldedData

Produce a FieldedData record for filePath corresponding to format.

  • format == ("tabular" | "ini")

procedure tabularLines(f) : C

Factory for a co-expression producing logical lines of a tabular file f.

procedure tabularFields(line, sep) : C

Factory for a co-expression producing fields from a logical line of a tabular file:

  • line is a logical line produced by tabularLines.
  • sep is the field separator; if omitted or &null, TAB is used.

procedure getTabular(typeName, tsvPath, colL, sep, dflt) : L

Produce L of RecTable from a tabular file

  • typeName: the first result to be produced by RecTableType(T), s
  • tsvPath : the path to the tabular data file, s
  • colL : (optional) columns to select, L of i
  • sep : (optional) separators, c
  • dflt : (optional) default value for RecTable fields, x

procedure iniLines(f) : C

Factory for a co-expression producing logical lines of an INI file f.

procedure iniFields(line) : C

Factory for a co-expression producing fields from a logical line of an INI file

  • line is a logical line produced by iniLines.

procedure getIni(ini) : T (two dimensional)

Parse an INI file at path ini into a table of tables

fileDirIo.icn

Procedures to manipulate files, directores, and their paths.

procedure alterExtension(fn, old_ex, new_ex) : s1, ...

Produce modified fn, substituting new_ex for old_ex

  • If new_ex is "", the trailing period will be removed.

procedure directory_seq(name) : s1, ...

Produce name(s) that name a directory

procedure prog_path_parts() : s1, s2

Suspend location then name of program file.

procedure path_atoms(path) : s1, ...

Suspend root, subdirectories, filename for a directory path

procedure path_constructP{expr} : s1, ...

Construct paths from sequences

procedure cmd_separator() : s

Return platform-specific command separator

procedure path_separator() : s

Return platform-specific path separator

procedure pwd() : s

Return platform-specific path to the current directory

iimage.icn

Procedures to transform data structures into includable Icon declarations and statements.

procedure iimage(x) : s

  • Produce Icon code to reproduce value x, if possible

procedure idump(f, x[]) : (writes to \f | &errout)

  • Write Icon code to reproduce values in list x to f if it is a file; otherwise to &errout and f is discarded.

LiComboP.icn

Procedures to suspend lists combining sequences.

procedure LiP(A) : L1, ...

  • Suspend lists combining infinite sequences. LiP:
    • evaluates in a "breadth first" manner to ensure that all values of finite sequences will eventually be produced even when some sequences are infinite.
    • uses memoization to avert the need to evaluate each sequence more than once.
    • uses wora(LiP) to determine whether to use LiFiniteP (the default) or nAltP to combine memoized results.
    • requires that wora.icn be previously included, for wora(id)

procedure LiFiniteP(LofC) : L1, ...

  • Recursively suspend lists combining finite seqs;
    • does not enforce "breadth first" evaluation.

procedure nAltP(LofC) : L1, ...

  • Recurrently suspend lists combining finite seqs;
    • does not enforce "breadth first" evaluation.

RecTable.icn

Procedures to produce/manipulate record-like tables.

procedure RecTable(rec_name_s, rec_fields_L, rec_data_L, rec_default_x) : T

Produce a table with record-like aspects:

  • rec_name_s: the "type" of the RecTable
  • rec_fields_L: a list of the field names
  • rec_data_L: an optional list of values to assign to the fields
  • rec_col_iL: an optional list of column numbers to choose defaults to all
  • rec_default_x: default value for table members

procedure RecTableType(x) : s1, S2, s3, ...

For RecTable, produce:

  • name
  • set of all fields
  • each field

For non-RecTable, return type(x).

procedure RecTableFields(x) : s1, ...

Produce RecTable's field names.

  • This will fail for a non-RecTable.

procedure RecTableFieldsL(x) : L

Return a list of the values produced by RecTableFields(x).

  • This returns an empty list when x is not a RecTable instance.

procedure RecTableFieldVals(x) : s1, ...

Produce RecTable's field values.

  • This will fail for a non-RecTable.

procedure RecTableFieldValsL(x) : L

Return a list of the values produced by RecTableFieldVals(x).

  • This returns an empty list when x is not a RecTable instance.

procedure RecTableColTypeCheck(x, type_name, col_name, preamble) : x

Return x, except abort when x is not instance of type_name:

  • x : value whose type is to be checked
  • type_name: expected string for RecTableType(x)
  • col_name : name of identifier-under-test
  • preamble : initial string for error message; defaults value of name RecTablePreamble.

procedure RecTableConstructorC(rec_name_s, rec_fields_L, rec_default_x) : C

Produce a C that, when receiving a transmitted list of values (of the same length as rec_fields_L), produces a RecTable instance:

  • rec_name_s the "type" of the RecTable
  • rec_fields_L a list of the field names
  • rec_col_iL an optional list of column numbers to choose, defaults to all
  • rec_default_x default value for table members

rpn.icn

Procedures to embed RPN-based (Forth-like) interpreter into Icon programs; can also be run in REPL.

This file may be used to embed RPN-scripted access to Icon procedures and operators, in a manner reminiscent of Forth.

  • This needs full and user-friendly documentation, which deserves its own file.
  • Words may be composed from existing words.
    • Words could be composed to conform to Forth standards...
    • New word definitions replace former definitions.
    • There is no forget yet.
    • The colon in a definition goes after the string naming the new word, e.g.,
      • "hi" : "hello world" . cr ;

See the following to get started:

  • tests/test_rpn.icn
  • tests/test_rpn.rpn
  • rpn_core.rpn
  • rpn.icn

This work was inspired by Steve Wampler's "A (small) RPN calculator" example https://sourceforge.net/p/unicon/mailman/message/6144067/ and R. G. Loeliger's Threaded interprtive languages (1981, BYTE Books) https://lccn.loc.gov/80019392.

run rpm.icn with REPL

To run this "stand-alone" in a "read, evaluate, print, loop" (REPL), I put the following in ~/bin/rpn:

LPATH=~/src/aceincl icon -P '
# run rpn.icn

# Define procedure main(args) that imports:
#   - ~/.rpn/*.rpn
#   - any .rpn files specified as arguments
# and executes standard input if either:
#   - *args = 0
#   - "-" == !args
$define RPN_MAIN 1
$include "rpn.icn"

# required by rpn.icn
$include "fileDirIo.icn"
'

then I made it executable:

chmod +x ~/bin/rpn

so that I can run it with:

~/bin/rpn

If you have rlwrap (https://github.com/hanslub42/rlwrap) installed (or built), and you change the first line above to

LPATH=~/src/aceincl rlwrap icon -P '

then you can get proper interpretation of the arrow keys in the REPL loop.

runningStats.icn

These procedures support computing summary statistics for normally distributed data using "Welford's online algorithm", porting code from Wikipedia.

ref: https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Welford's_online_algorithm

record welford_running(count, mean, M2)

  • record accumulating online results without persisting raw data

record welford_cumulative(n, mean, variance, sampleVariance, SD, SE)

  • record of statistical results extracted from welford_running

procedure welford_new()

  • produce an initialized welford_running record

procedure welford_add(W, x)

  • produce an updated welford_running record
    • W a welford_running record
    • x the next value to add to the record

procedure welford_get(welford_running)

  • produce welford_cumulative record summarizing normal statistics
  • for the series of x provided to welford_add
    • welford_running a welford_running record updated by welford_add

selectRecordFromListByField.icn

Procedure to produce records from a list of records (or a list of tables), matching specified criteria.

  • This is currently NOT coded efficiently, so only use it on small lists or tables.
  • Also, at present, the co-expression is refreshed and (as an apparent consequence) leaks memory.
  • For a better way to do this, see fix_selectRecordFromListByField.icn, which I will eventually apply here instead.
    • Even so, there is yet the need to incorporate a "fuzzy binary search" to speed things up immensely for larger lists or tables.

procedure selectRecordFromListByField(Lfrom, sField, Ctest) : R1, ...

  • Produce matching records (or tables) X
    • from list Lfrom (type(Lfrom[i]) == "record" | "table")
    • where X[sField] @ Ctest succeeds

procedure selectRecordFromListByFieldL(Lfrom, sFieldL, Ctest) : R1, ...

  • Produce matching records (or tables) X
    • from list Lfrom (type(Lfrom[i]) == "record" | "table")
    • where this succeeds:
      L := []; every put(L, X[!sFieldL]); L @ Ctest

vnom.icn

"Nominal vector", i.e., a list whose elements may be accessed by rank (index) or name (key).

A use case for this construct might a dynamically-defined record (i.e., an ordered list of key-value pairs), such as might be used to represent a row returned by an SQL query.

Through use of a Lua-inspired "metatable", operations on this structure may be defined or extended with a few message-handler-extension functions. Note that a metatable may be shared among several VNom instances to give them identical behavior; for this reason, the copy constructor copies a reference to the metatable rather than making a copy of the metatable. Thus, behavior of the set of instances may (even dynamically) be modified by changing a single structure.

procedure vnew(Original:T, Type:s, ID:s, Metatable:T, Disposable:s, Kind:s) : V

Construct a new VNom instance.

  • Original:T
    • &null | table | VNom
  • Type:s
    • Type property
  • ID:s
    • ID property
  • Metatable:T
    • table mapping message strings to message-handler procedures
    • By design, when Original is another VNom, vnew copies a reference to the metatable rather than the metatable itself.
  • Disposable:n?
    • if not null, set Disposable property to "yes"
  • Kind:s
    • Kind property

procedure vmsg(VNom:V, Message:s, args[]) : x

Send messages to update or interrogate the VNom instance.

  • vmsg(V, "!" ) : x1, ... # generate values in order keys in L
  • vmsg(V, "*" ) : i # produce number of values
  • vmsg(V, "get" | "pop" ) : x # pop value, discarding key
  • vmsg(V, "pull" ) : x # pull value, discarding key
  • vmsg(V, "push", x1, x2) : V # push value with key
  • vmsg(V, "put", x1, x2) : V # put value with key
  • vmsg(V, "key" ) : x1, ... # generate keys in order keys in L
  • vmsg(V, "keylist" ) : L # copy of L of ranked keys
  • vmsg(V, "bykey", x ) : s # value, assignable by key
  • vmsg(V, "byrank", i ) : s # value, assignable by rank (index)
  • vmsg(V, "kind" ) : s # Kind property, assignable
  • vmsg(V, "id" ) : s # ID property, assignable
  • vmsg(V, "type" ) : s # Type property, assignable
  • vmsg(V, "image" ) : s # image property
  • vmsg(V, "metatable" ) : s # Metatable, assignable `

wora.icn

Procedure to produce a value that can be read globally but can be reset only by the co-expression that set it it initially.

procedure wora(id,del) : x (lvalue or rvalue)

  • Set or read a globally visible read-only value,
    • which is resettable by the C that creates it.
  • id identifies the value; it is a key to a static table.
  • del signifies that the value is to be deleted, but only when specified by the creator.
    • Otherwise, this argument is ignored.

Legacy Source Code Control

If you are still using Git rather than the best thing since CVS, then you may need the following to recover from the mess that Git Submodule can create if you are not very careful.

Git Submodule - some practical reminders

Reference: http://openmetric.org/til/programming/git-pull-with-submodule/

  • To add a submodule to a repo, do, e.g.:
    git submodule add [email protected]:eschen42/aceincl.git
  • For a repo with submodules, pull all submodules using
    git submodule update --init --recursive
    for the first time. All submodules will be pulled down locally.
  • To update submodules, use
    git submodule update --recursive --remote
  • To "commit" new changes in a submodule to the client project:
    1. Make sure that there are no unsaved changes in the submodule (are any files in the sandbox different from the committed code?). a. If so, commit and push.
    2. Next:
      git submodule update --recursive --remote
    3. Now it's possible to add and commit changes to the client project.
  • What's changed in the submodule? (or "Has the commit for the submodule changed?" or something):
    git diff --submodule

Ichabod Crane and the HEAD-less Repository

Reference: https://www.loekvandenouweland.com/content/head-detached-from-origin-master.html

If a submodule is in a "detatched HEAD" state (and it is not 1789), there are two courses of action that to take, depending on whether commits require rescuing.

If there is no need to push commits to the submodule to a remote git repository, something like the following should work, e.g., to reattach origin/main from the remote for submodule aceincl:

cd aceincl
git branch -la
git checkout remotes/origin/main
git status
git pull
git status

If there are commits to preserve, the process is more involved; see the reference, the gist of which is something like:

  1. Put the commits onto a branch:
    git branch fix-detached-HEAD $(git log | sed -n -e '/^commit/{s/commit[ ]*//; p; q}; d')
  2. Get the main or master branch, as appropriate for your repo:
    git checkout main (or git checkout master)
  3. Re-establish remote tracking:
    git fetch
  4. Review changes if necessary:
    git diff fix-detached-HEAD
  5. Merge the changes to the remote-tracking non-HEAD-less branch:
    git merge fix-detached-HEAD
  6. Push changes to the remote:
    git push --set-upstream origin master
    or git push --set-upstream origin main