Hacking NaaN

Hacking NaaN
All interesting programming languages provide a good hacking environment and NaaN endeavors to continue this fine tradition.
Hacking is a skilled activity focused on reaching a goal using unconventional and preferably clever means. The term hacker comes from Yiddish, referring to someone so crude as to make furniture with an axe. There is an implication that hacking is ugly, which it can be, but a skilled hacker can also find efficient solutions that elude more conventional thinkers. Hacking often involves breaking rules, but not necessarily laws despite the persistent media narrative to the contrary.
Programming languages are designed around rules. There are rules for syntax, and semantics, and data types, and how language features may or may not be used together. When you don't follow the rules, or when diverse facets of your program conflict in obscure ways under the rules, then errors are emitted and you are required to modify your program to conform. People make a lot of mistakes, and myriad rules can help catch them and improve program quality. Rules can also improve uniformity, which is often helpful in building and maintaining software with teams.
Unfortunately rules can also limit creativity. There is a sizeable constituency of software practioners who believe that creativity is overrated, at least compared to the value of rules. Creativity advocates seek the liberty to pursue their own vision without restrictions. There is definitely a tension here.
Programming languages offer different positions on the spectrum between liberty-oriented at one end, and rules-oriented at the other. Extreme liberty-based languages don't offer much protection. The attitude is that programmers know what they want and deserve to get it good and hard.[1] Extreme rules-based languages assume the programmer may be an enemy saboteur, so everything not specifically permitted is prohibited. Each language and point on the continuum has its advocates.
NaaN Philosophy
NaaN strives to be the easiest, most enjoyable path for creatively expressing your software ideas. This implies a position closer to the liberty end of the spectrum. NaaN's guiding principle is to make appropriate paths available and then trust the programmer to select the best one.
- Common tasks should be easy.
- Sophisticated tasks should be straightforward.
- Difficult tasks should be possible.
- Nothing can be forbidden.
Flexibility is important because no language design can anticipate every need a programmer might have in the future. If all paths forward are blocked then a hacker will either chop their way to the goal or throw the whole mess away and start again in a more habitable place.
NaaN accommodates hacking by providing multiple layers and a variety of tools for exploration and navigation. For example, you can view all NaaN code in source form even if the original source files are not available. This lets you take things apart to see how they work and then put them back together differently.
Navigating NaaN
NaaN has two primary methods of human interaction, through the terminal interface or through NaanIDE and its GUI. This post focuses on the terminal because it's easy to host on a web page without a backend.
You can start exploring NaaN using its standard global variables:
Naan
is a dictionary of all inbuilt procedures by category. These are globally available. TypeNaan
into the REPL to see the whole thing,Naan.*
to see the names of the categories, orNaan.<category>.*
to see just one.App
is a dictionary that belongs to the current application for storing useful shortcuts. TypeApp
to display it.Dialect
points to the object controlling the current language. See the post Dialects In Naan for examples of how this can be used.
Examples:
Play-lingo> Naan.*
$: ("exec", "info", "symbol", "tuple", "number", "string", "array", "dictionary",
"local", "host", "stdio", "external", "debug", "module", "runtimelib")
Play-lingo> App
$: {
version : "1.0.0-dev+309",
cache : "a835b2fdf0a162578d88066a33c9bc01",
naanTerm: { NaanTerm: NaanTerm },
term : Object{13} }
Play-lingo> Dialect.*
$: ("ns", "name", "grammar", "operators", "exunparse", "parser", "unparser",
"parse", "parseErrorString", "unparse", "print", "defhook", "defunparse",
"redefine", "defatt", "defsym", "require", "info", "destroy", "derive",
"module")
JavaScript interop
JavaScript interoperability allows NaaN to interact freely with JavaScript libraries and the browser or NodeJS environment.
Here in the browser js.w
returns the global window
object. To see all of the defined fields of an object or dictionary, use the operator .*
. For example:
Play-lingo> js.w
$: [object Window]
Play-lingo> js.w.location
$: [Location http://localhost:8009/run/naanTermDev/naanterm/embed.html]
Play-lingo> js.w.location.*
$: ("valueOf", "ancestorOrigins", "href", "origin", "protocol", "host", "hostname",
"port", "pathname", "search", "hash", "assign", "reload", "replace",
"toString")
By default NaaN does not import native JavaScript objects to NaaN, but you can request conversion with new(<jsobject>)
. The REPL fully displays the resulting NaaN object:
Play-lingo> new(js.w.location)
$: {
href : "https://naanlang.org/naanlang/naanterm/embed.html",
origin : "https://naanlang.org",
protocol: "https:",
host : "naanlang.org",
hostname: "naanlang.org",
port : "",
pathname: "/naanlang/naanterm/embed.html",
search : "",
hash : "",
assign : [Function assign],
replace : [Function replace],
reload : [Function reload],
toString: [Function toString],
valueOf : [Function valueOf] }
Create JavaScript objects within NaaN using xnew
. You can explore the available methods on a JavaScript object by listing the keys as shown.
Play-lingo> xnew(js.w.URL, "https://www.naanlang.org")
$: [URL https://www.naanlang.org/]
Play-lingo> $.__proto__.*
$: ("toJSON", "toString", "href", "origin", "protocol", "username", "password",
"host", "hostname", "port", "pathname", "search", "searchParams", "hash",
"constructor")
Finally, no JavaScript hack would be complete without eval
:
Play-lingo> js.w.eval("alert('Hello World!')");
$: undefined
REPL and Debugger
NaaN's terminal provides an ordinary REPL that evaluates and prints expressions that you type. However there is also a "slash executive" with useful queries and commands that are inconvenient to write as expressions. Start by typing /help
into the terminal:
Play-lingo> /help
About Naan: https://github.com/naanlang/naan#readme
/commands:
/ch[mod] [<module>] - change active module
/d[ebug] - enter debugger
/help [<command>] - help [command]
/i[nfo] [<topic>] - info on topic
/op[tions] - view or modify options
/r[estart] - restart REPL
/q[uit] - decamp / depart / absquatulate
If you manage to enter the ndb command-line debugger, you'll need to know how to get out again. Type c
to continue, q
to stop executing, or help
(/help
) for instructions:
Play-lingo> /d
(ndb-1) /help
help topics:
breakpoints - work with breakpoints
exceptions - work with exceptions
execution - stepping and continuing execution
eval - evaluating and printing expressions
help - using help
info - print debugger information
list - list procedure source
locations - syntax for procedure location references
stacks - backtrace and stack frame details
quit - quitting current execution
(ndb-1) c
Play-lingo>
Playpen
The hints above provided some starting points, but there is a lot more to discover. Please experiment in the terminal below. For example, App.term
is the object that operates the embedded terminal. Try typing these:
App.term.nrh_break.style.backgroundColor="red"
App.term.nrh_openout.click()
Happy Hacking!
As always, if you wish to investigate further, the NaaN interpreter and the NaanIDE IDE are available under the MIT license.
With apologies to H.L. Mencken ↩︎
Comments ()