* Add MT_BYTES mlrval type: foundation and disposition tables First step toward a first-class bytes type in the DSL (#1231). Adds MT_BYTES (payload []byte, rendered as lowercase hex in all output formats, JSON-encoded as a hex string), extends every disposition matrix/vector with the new row/column -- real cells for comparison, sorting, and dot-concat of bytes with bytes; type-error stubs elsewhere -- and adds sweep tests asserting no table has nil cells, since Go zero-fills short array literals when MT_DIM grows. Bytes values are not yet constructible from the DSL; b"..." literals and constructor/codec functions follow in subsequent commits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add b"..." bytes-literal syntax to the DSL Adds a bytes_literal token to the grammar (regenerating the PGPG lexer and parser) and a BytesLiteralNode in the CST which evaluates to an MT_BYTES mlrval. Escape handling reuses UnbackslashStringLiteral, which is already byte-oriented: b"\xff" is the single byte 0xff. Unlike string literals, bytes literals never participate in regex-capture replacement. A bare identifier b is unaffected. Part of #1231. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add bytes DSL functions: conversions, codecs, and bytes-aware built-ins - bytes(x) converts strings to bytes; string(b) reinterprets raw bytes as UTF-8 text (the reverse) - base64_decode now always returns bytes (superseding the interim string-or-hex behavior); base64_encode accepts string or bytes - New hex_encode/hex_decode functions - is_bytes and asserting_bytes predicates - md5/sha1/sha256/sha512 accept bytes, hashing the raw payload - strlen of bytes is the byte count; substr/substr0/substr1 on bytes slice by byte position and return bytes The Cyrillic-LDAP scenario from #1231 now works without exec workarounds: string(base64_decode($x)) recovers the text, and binary payloads survive undamaged as bytes. Closes #1231. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Add bytes-type docs and regression cases Documents the bytes type on the data-types page, regenerates the function-reference/man-page material, and adds regression coverage: literal escape forms, operators (concat/compare/slice/sort and type errors), conversions and codec round-trips, and CSV-to-JSON output rendering of bytes fields. Part of #1231. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Reposition MT_BYTES to sort adjacent to MT_STRING in the type enum MT_BYTES was appended after MT_ABSENT for index stability; move it right after MT_STRING instead, since that's where it conceptually belongs and where it already sorts in the cmp disposition matrices. Mechanically re-derive all ~40 disposition tables in pkg/bifs and pkg/mlrval accordingly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix windows CI * fix merge --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| assignments.go | ||
| ast_types.go | ||
| block_exit.go | ||
| blocks.go | ||
| builtin_function_manager.go | ||
| builtin_function_manager_json.go | ||
| builtin_functions.go | ||
| collections.go | ||
| cond.go | ||
| doc.go | ||
| dump.go | ||
| emit1.go | ||
| emit_emitp.go | ||
| emitf.go | ||
| env.go | ||
| evaluable.go | ||
| filter.go | ||
| for.go | ||
| functions.go | ||
| hofs.go | ||
| if.go | ||
| keyword_usage.go | ||
| keyword_usage_json.go | ||
| leaves.go | ||
| lvalues.go | ||
| print.go | ||
| README.md | ||
| root.go | ||
| signature.go | ||
| statements.go | ||
| subroutines.go | ||
| tee.go | ||
| types.go | ||
| udf.go | ||
| uds.go | ||
| validate.go | ||
| warn.go | ||
| while.go | ||
See ../dsl/README.md for more information about Miller's use of abstract syntax trees (ASTs) and concrete syntax trees (CSTs) within the Miller put/filter domain-specific language (DSL).
Files
types.gois a starting point for seeing datatypes involved in the concrete syntax tree.IExecutableis the interface for executable nodes, such as assignment statements, or statement blocks (if-bodies, etc.).IEvaluableis the interface for evaluable expressions (e.g. right-hand sides of assignment statements).
root.gocontains the top-level logic for building a CST from an AST at parse time (cstRoot, err := cst.Build(astRoot)), as well as executing the CST on a per-record basis (cstRoot.Execute(runtimeState)). See also theputtransformer.
Notes
Go is a strongly typed language, but the AST is polymorphic. This results in if/else or switch statements as an AST is walked.
Also, when we modify code, there can be changes in the BNF grammar not yet reflected in the AST. Likewise, there can be AST changes not yet reflected here. (Example: you are partway through adding a new binary operator to the grammar.)
As a result, throughout the code, there are error checks which may seem redundant but which are in place to make incremental development more pleasant and robust.
During CST build from an AST, one starts from the AST root and walks down through the nodes of the AST. Within a caller method, there is an if/else or switch statement on the AST node type. (Example: is this a leaf node, like the string literal "abcd", int literal 3, field-name $x? Or a binary operator like +, or function call like cos?).
Different builder methods are invoked for leaves, operators, etc. There is also, redundantly, a precondition assertion within each builder method: the leaf-builder method checks to make sure it's given an AST leaf node to build from; the operator-builder method checks to make sure it's given an AST operator node to build from; etc. The caller and the callee are doing the same kinds of check, which might seem redundant. The callees return Go error in case there is something new in the caller which has not yet been implemented in the callee.
This is all done to make development more happy: when you see things like CST build: AST unary operator node unhandled you can check the code here and see what you need to do next to continue development.