NME language reference
NME has three syntax levels in one compiler. There is no mode switch: advanced Python, beginner NME, sentence NME, Korean, and English may appear together in one file or one block.
The compatibility rule
Valid Python always wins. NME asks a real Python parser whether a line is valid before matching easier syntax. A valid Python program therefore compiles byte-identically.
say = print
say("Python call")
if ready:
print("Python condition")
The three levels compile as follows:
| Level | NME | Python result |
|---|---|---|
| Sentence | repeat 3 times and show Hi | for _ in range(3): print("Hi") |
| Beginner | 3 times: say "Hi" | for _ in range(3): print("Hi") |
| Advanced | for _ in range(3): print("Hi") | unchanged |
Sentence level
Sentence syntax is for a first program. Quotes, commas, parentheses, braces,
equals signs, and colons are optional for the common tasks below. Normal
sentence punctuation ? and ! is accepted without quotes.
Show text and values
show Hello world!
Hello world show
보여줘 안녕하세요!
안녕하세요 말해줘
Please show me hello
run it →These print literal text. A name created earlier by an input or sentence assignment is inserted automatically:
ask name What is your name?
show Hello name!
이름을 물어봐 이름이 뭐예요?
안녕하세요 이름! 말해줘
run it →The result uses the value of name / 이름; other words stay literal.
Korean particles following a known name remain in the output.
If a line is clearly ordinary multi-word speech, NME can print it without an action word:
Hello everyone!
오늘도 반가워요!
run it →A line holding a single word prints too. It is valid Python — a name read and
thrown away — but a program that says nothing and then dies with a NameError
is nobody's intention, so NME prints the word. Two lines keep their Python
meaning: a name the program set earlier, and a word NME spells out itself
(say, end, skip, 목록).
The shortest conversation does not need a prompt or punctuation:
name ask
Hello name show
run it →For the gentlest possible first input, ask as a normal question:
What is your name?
What's your city?
Hello name!
run it →The matching target (name or city) is inferred from the question. Korean
questions such as 이름이 뭐예요, 내 이름은 뭐예요?, and
나이는 몇 살이에요? work the same way; 몇 살이에요? is also inferred as
나이. English How old are you? / How old am I infer age. The final ?
is optional. Use ask number when the answer must be converted to a number;
complex or ambiguous questions should use the explicit ask form.
Accepted output actions include show, display, tell, say, 보여줘,
말해줘, 말해주세요, 출력해, and 출력해줘. The precise beginner
spellings say expression and 말해 표현식 continue to treat a valid Python
expression as code.
Korean states its verb last, and several more words mean show it when they
stand there. They are read only at the end of a line, because at the front
they are nouns: 말하기 연습 is speaking practice and prints itself.
안녕하세요 말하기
안녕하세요 알려줘
안녕하세요 얘기해
안녕하세요 표시해
안녕하세요 띄워
run it →The shortest of them is one syllable. 말 is also the ordinary noun word,
so it is read as the verb only when nothing in front of it is making it a
noun — an adnominal ending in ㄴ/ㄹ, or a determiner. 그건 좋은 말,
무슨 말 and 내 말 keep every word they have:
안녕하세요 말
그건 좋은 말
무슨 말
run it →A message may also say where it goes. English writes on the screen after it
and Korean writes 화면에:
put hello on the screen
hello on the screen
안녕하세요 화면에
안녕하세요 화면에 띄워
run it →Some words a beginner reaches for are not output words, and NME says so
rather than printing them back. write already means the file statement
(write text to "notes.txt"), so guessing between the two would be worse than
asking:
output hello → I don't know what `output` does; did you mean `show`?
write hello → I don't know what `write` does; did you mean `show`?
echo hello → I don't know what `echo` does; did you mean `show`?
read hello → I don't know what `read` does; did you mean `ask`?
Only one word of message is claimed that way, so the ordinary sentences keep
working: write it down before you forget, read the instructions twice and
echo of the mountain all print themselves.
Ask for text or a number
ask name What is your name?
ask name, What is your name?
이름을 물어봐 이름이 뭐예요?
ask number age How old are you?
나이를 숫자로 물어봐 몇 살인가요?
run it →Natural prompts receive a separating space automatically. A comma is optional
for a plain-language prompt; quoted or expression prompts may use the precise
beginner comma form. Text input compiles to input(...); number input compiles
to int(input(...)).
Accepted actions include ask, prompt, 물어봐, 물어봐줘, 질문해, and
입력받아. Korean target particles 을 and 를 are removed from the variable
name. The short form 물어 also works; it is read exactly, never as a repaired
misspelling, because two syllables is one edit away from half the language.
read, get, 받아 and 여쭤봐 are asking words too, but only on a line that
really asks — one ending in a question mark, or in a Korean question ending.
Without one, read the label on the bottle and get well soon are sentences:
read name what is your name?
get name what is your name?
이름을 받아 이름이 뭐예요?
이름을 여쭤봐 이름이 뭐예요?
이름 물어 이름이 뭐예요?
run it →Save a value
인사는 안녕하세요
정답은 7
set greeting to Hello
set answer to 7
greeting save Hello
이름 저장 민수
score add 1
subtract 1 from score
run it →These become normal assignments. Target-first speech such as name save Mina
or 이름 저장 민수 is also supported. Numbers and clear expressions remain code;
plain words become text. A saved name is available for later sentence
interpolation and conditions.
The everyday verb saves a value too. Korean closes the sentence with 해,
하자 or 합시다, and the value has to carry 로/으로 or 라고/이라고
saying what the name becomes — without that mark 밥을 맛있게 해 is somebody
asking for the rice to be nice, and stays a sentence. English writes becomes
after the name, or opens with call it:
이름을 5로 해
점수를 0으로 하자
인사를 안녕하세요라고 하자
name becomes 5
call it name 5
run it →A word a sentence may never turn into a name stops the reading, so
Call it a day. and Call it what you like. still print themselves.
Small value changes can also be written without +, -, or =. Use
score add 1, add 1 to score, or score increase by 1; subtraction uses
subtract 1 from score.
Lists
A list is made with list of / 목록, and an empty one with an empty list /
빈 목록:
set friends to list of Mina, Ada
친구들은 목록 민수, 지안
set pals to an empty list
할일은 빈 목록
run it →Once a name holds a list, the sentences that read it and rearrange it work on it:
append Grace to friends
친구들에 지수 넣어
remove Mina from friends
친구들에서 민수 빼
show how many friends
친구들 개수 말해줘
sort friends
친구들 정렬해
reverse friends
친구들 거꾸로 해
shuffle friends
친구들 섞어
show the first of friends
친구들 첫 번째 말해줘
show the last of friends
친구들 마지막 말해줘
show item 2 of friends
친구들 2번째 말해줘
show the total of scores
점수들 합 말해줘
show the biggest of scores
점수들 중 가장 큰 것 말해줘
show friends joined by comma
친구들을 쉼표로 이어 말해줘
show friends joined together
친구들을 붙여 말해줘
The separators are comma, space and newline (쉼표, 빈칸, 줄바꿈), and
joined together / 붙여 puts nothing at all between the items, which is how
a row of stars is drawn. A join that names no separator is refused with
E0233: show friends joined used to print friends joined back at you,
which reads like success and is not.
Items are counted from one. the first of friends is item 1 of friends,
and both become friends[0]. There is no item 0: writing one is refused with
E0229 rather than quietly handing back the last item, which is what Python's
friends[-1] would do.
One item can be given a new value, counted from one the same way. The position may be a number or a name the program made, and the new value is anything a saving line accepts:
set values to list of 1, 2, 3
set item 2 of values to 9
change the last of values to 0
show values
수들은 목록 1, 2, 3
수들 2번째를 9로 바꿔
수들의 첫 번째를 0으로 바꿔
수들 말해줘
run it →set item 2 of values to 9 becomes values[1] = 9, and 수들 순서 번째를 0으로 바꿔 becomes 수들[순서 - 1] = 0. A record has no second item, so the
same line on a record is refused with E0234. Before this spelling existed,
set item 2 of values to 9 saved the words 2 of … to 9 into a name called
item, and the program ran.
One item picked at random is a value like any other — something to show, to save, or to compare:
set songs to list of Hey Jude, Yesterday, Let It Be
show a random one of songs
set song to a random item from songs
노래들은 목록 봄날, 밤편지, 좋은날
노래들 중 아무거나 말해줘
고른노래는 노래들에서 아무거나
run it →Both become __import__("random").choice(songs). Like every list reading, it
needs a name the program already made a list: a random one of these days
stays a sentence.
Two of these read a list inside a condition:
if friends contains Mina
만약에 친구들에 민수가 있으면
if friends is empty
만약에 친구들이 비었으면
The list may also come first, which is the order Korean uses and the one a
beginner reaches for after reading friends.append("Mina"). Korean may leave
the 에 off, the way speech does:
friends append Mina
친구들 민수 넣어
run it →Every one of them needs a name the program already made a list. That is
the whole reason sort out your things, the first of many,
그릇 설탕 넣어 and 친구들 이야기를 들었습니다 stay ordinary sentences and
print themselves. Using
one on a name that is not a list is refused with E0231, so a mistake is a
message and not a program that means something else.
how many is also a value and a condition, not only something to show:
set total to how many friends
총합은 친구들 개수
if how many friends is greater than 3
만약에 친구들 개수가 3보다 크면
Records
A record holds many named values at once, each one under a name of its own. Python calls it a dictionary.
set ages to an empty record
put Mina at 90 in ages
show Mina in ages
show how many ages
remove Mina from ages
run it →나이표는 빈 표
나이표에 민수를 90으로 넣어
나이표의 민수 말해줘
나이표 개수 말해줘
나이표에서 민수 빼
run it →The word record (표, and table in English) is only the kind of thing
being made where a value is being saved. Everywhere else it is a word
somebody wrote: I keep a record of everything I read and
표는 두 장 남았습니다 print themselves.
Most of a record's grammar is spelled exactly like a list's — how many /
개수, remove / 빼, contains / …에 …가 있으면, for each / …마다 반복해 — and the compiler decides which is meant from the kind the name holds,
never from the wording. That is the point: a reader should not have to remember
which spelling belongs to which container. A record line written on a list is
refused with E0234, because appending Mina를 90 to the list as one piece of
text would be a program nobody wrote.
A record has no order and nothing to add up, so the total of, the biggest of, the first of and sort are list-only and stay refused for a record.
Looping over a record hands back its names, exactly as Python does, so the value is read back inside the loop:
set ages to an empty record
put Mina at 90 in ages
for each name in ages
show name in ages
end
run it →A name ordinary Python wrote as ages = {} is a record to all of these too.
Arithmetic in words
set total to 10
set done to 3
set left to total minus done
show total plus done times 2
set half to total divided by 4
if total minus done is greater than 5 then show Nearly there
전체는 10
순서는 3
남은수는 전체 빼기 순서
전체 더하기 순서 곱하기 2 말해줘
run it →plus, minus, times, multiplied by and divided by — in Korean
더하기, 빼기, 곱하기 and 나누기 — are Python's +, -, * and /.
set left to total minus done becomes left = total - done, and
show total minus done prints 7. Several of them in a row follow the order
a maths book uses, so total plus done times 2 multiplies first. divided by
is Python's / and answers with a fraction; when you need a whole number,
write the whole number of total divided by 4 (전체를 4로 나눈 몫), which is
Python's //.
Every side has to be a written number or a name the program already made. If
any side is anything else, the words are the text they always were:
설탕 빼기, show one plus one equals two and show the price minus tax
print themselves. The arithmetic is read as the whole value of a saved name,
as the whole of what show/말해줘 prints, and on either side of a
comparison; inside a longer sentence — show You have total minus done left —
it stays words. The repeat forms that say times (repeat 3 times,
3 times Welcome, name repeated 5 times) are unchanged.
What is left over
show the remainder of pile divided by 4
쌓인돌을 4로 나눈 나머지 말해줘
set left to the remainder of pile divided by 4
if the remainder of pile divided by 4 equals 0
만약에 쌓인돌을 4로 나눈 나머지가 0과 같으면
The remainder is % in Python, and it decides most counting games. It is a
value, so it works in output, in a saved name, and in a condition. The number
being divided by has to be a written number or a name the program already made.
Working with text
show the length of name
이름 길이 말해줘
show name in capitals
이름 대문자로 말해줘
show name in small letters
이름 소문자로 말해줘
run it →These read any saved name, not only a list. the length of gives how many
characters there are; the other two give the same text with its letters
changed. All three are values, so they may be saved or compared as well as
shown.
Text can also be cut into a list, which is the step after reading a file:
set names to memo split by line
이름들은 메모를 줄마다 나눈 것
set fields to line split by comma
칸들은 줄을 쉼표로 나눈 것
set words to sentence split by space
말들은 문장을 빈칸으로 나눈 것
run it →split by line / 줄마다 is Python's splitlines(), which copes with a file
that ends in a newline and with the Windows line ending. The others cut on the
separator itself: a comma here is "," and not ", ", because a line read
back out of a file says Mina,Ada. What a split saves is a list, so
how many names / 이름들 개수 works on it straight away.
And one piece of text can be written over and over:
set bar to star repeated 5 times
막대는 별표를 5개 붙인 것
show star repeated 20 times
별표를 20번 붙인 것 말해줘
run it →5번 may be written here even though it means five times in a counted loop,
because this is a noun phrase closing with 붙인 것 and no loop ever says that.
The text is wrapped in str(...) first, so a name holding 3 gives "33333"
and not 15: the sentence asked for five copies, not for arithmetic.
Repeat
One sentence on one line:
repeat 3 times and show Again
3번 반복해서 다시 말해줘
3 times 반복해서 mixed 말해줘
3 times Welcome to NME
3번 안녕하세요
run it →When the count comes first, the plain words after it are repeated output. This
is the easiest form; add show/말해줘 when you want the meaning to be
visibly explicit.
loop, iterate and cycle, and Korean 돌려 and 되풀이해, are repeat words
too, but only with the count standing beside them — English after the word,
Korean before it. Without the count they are ordinary verbs, so
loop the ribbon around twice and 돈을 돌려 주세요 keep every word they have:
loop 3 times
3번 돌려
3번 되풀이해
3번 되풀이해서 안녕 말해줘
Several lines use indentation but no colon:
repeat 3 times
show First
둘째 말해줘
3번 반복해
show mixed
run it →repeat, 반복, 반복해, and 반복해서 may be mixed with times or
번. The count is any valid Python expression.
A block written with a colon and ordinary indentation takes its branches the same way, in both languages:
만약 score > 10:
print(1)
아니면 만약에 score == 0:
print(2)
아니면:
print(3)
run it →skip / 건너뛰어 and break / 멈춰 work inside an indented 3 times:
block too. Until this release they were left as bare Python names there, so
the program compiled and then raised NameError.
A loop with no count at all is written repeat forever / 계속 반복해, and
break / 멈춰 is the way out of it:
repeat forever
show still going
break
계속 반복해
아직 진행 중 말해줘
멈춰
run it →A loop that counts gives each number to a name. Both ends are counted, so
from 1 to 10 is ten turns and the last one is 10:
count n from 1 to 10
show n
repeat with n from 3 to 1
show n
수를 1부터 10까지 세면서 반복해
수 말해줘
run it →The first becomes for n in range(1, 11):, and 3 to 1 counts down with
range(3, 0, -1). Korean may leave the particle off the counter (수 1부터 10까지 세면서 반복해) when the word could not be carrying a different one.
Either end may be a name the program made; then the direction is decided when
the loop starts, in the same line of Python:
for n in (range(1, top + 1) if 1 <= top else range(1, top - 1, -1)):. The
beginner header is the same words with a colon — count n from 1 to 10: /
수를 1부터 10까지 세면서: — and the one-line form is
count n from 1 to 3 and show n / 수를 1부터 3까지 세면서 반복해서 수 말해줘.
count sheep from dusk to dawn names nothing to count with and stays a
sentence.
The compact colon form can also use an explicit closing word, so indentation is optional while you are learning:
3 times:
show First sentence
둘째 문장 말해줘
end
run it →The same flat form works with Korean 3번: and 끝. A normal Python for or
if line with a colon remains Python and keeps Python's usual indentation
rules.
A block without indentation
Indentation is useful when you are ready for Python, but it is not required
for the first programs. Put end (or 끝) on its own line to close an easy
block. This form also introduces the control flow needed to grow into Python:
score = 0
while score < 3
show score
score = score + 1
end
if ready and score > 2
show Go
else if score == 0
show Try again
else
show Not yet
end
while ready or waiting
show Still working
break
end
run it →동안, 만약, 아니면, 아니면만약에, 멈춰, and 끝 are Korean
spellings of the same ideas. and/그리고 and or/또는 may be mixed in
one condition. A block
may still use ordinary four-space indentation; the explicit end form is the
beginner-friendly bridge when indentation is the part that feels hardest.
Spoken Korean can put the loop ending after its subject too, as in
준비하는동안, 준비 하는 동안, or 준비 동안. The English while keyword
may head a Korean sentence condition with the same ending, as in
while 점수가 3보다 작을 동안.
Conditions
Colon-free blocks:
if ready
show Go
만약에 이름이 있으면
안녕하세요 이름 말해줘
run it →Inline sentences use then or a Korean connecting ending:
if score is greater than 10 then show You won
만약에 점수가 10보다 크면 성공 말해줘
run it →An else may follow a one-line if written directly above it, at the same
indent. That is the shortest thing a beginner can write that says what they
mean, and the Python it becomes is ordinary:
set hp to 5
if hp is greater than 0 then show alive
otherwise show down
체력은 5
만약에 체력이 0보다 크면 살아있음 말해줘
아니면 만약에 체력이 0과 같으면 아슬아슬 말해줘
아니면 쓰러졌습니다 말해줘
run it →more than and fewer than compare the way greater than and less than do,
and Korean adds 많으면/넘으면 and 적으면 to 크면 and 작으면:
if score is more than 10 then show You won
if score is fewer than 10 then show Not yet
만약에 점수가 10보다 많으면 성공 말해줘
만약에 점수가 10보다 적으면 아직 말해줘
run it →You may also start with the subject when that reads more naturally:
score is greater than 5 then show high
name exists then show Welcome name
색이 빨강과 같으면 맞아요 말해줘
run it →The subject-first form is limited to a clear comparison, existence check, or
unmistakable action body. Ordinary speech such as Hello then world remains
prose.
Korean can shorten the comparison ending without changing the meaning:
이름이 철수면, 이름이 철수라면, and 준비가 거짓이면 are accepted. Spoken
particles may be separated too (이름 이 철수 면), and a bare subject can use
준비면 for a truthy condition. A one-syllable name the program made works the
same way — 만약에 비면, 만약에 비라면, 만약에 비이면 test 비 exactly as
if rain tests rain; a word the program never made keeps the reading it had.
A bounded spoken typo such as 있으먄, 철수먄, or 만악에 is recovered when
there is only one clear condition.
Either side of a comparison may be a reading or arithmetic, and the right side takes every reading the left side takes:
set word to hi
set longest to hello
if the length of word is greater than the length of longest then show longer
말은 안녕
가장긴말은 하이
만약에 말 길이가 가장긴말 길이보다 크면 더 길다 말해줘
run it →A reading on the right is read only from a name the program made, so
if word equals the length of cake still compares with the words
the length of cake.
Supported sentence comparisons:
| English | Korean | Meaning |
|---|---|---|
if name exists | 만약에 이름이 있으면 | truthy value |
if name missing | 만약에 이름이 없으면 | falsey value |
if score equals 10 | 만약에 점수가 10과 같으면 | == |
if score is not equal to 10 | 만약에 점수가 10과 같지 않으면 | != |
if score is greater than 10 | 만약에 점수가 10보다 크면 | > |
if score is less than 10 | 만약에 점수가 10보다 작으면 | < |
if score is less than or equal to 10 | 만약에 점수가 10보다 작거나 같으면 | <= |
if score is greater than or equal to 10 | 만약에 점수가 10보다 크거나 같으면 | >= |
when condition, 만약 condition, 만약에 condition, and the mixed
if 조건 are all valid. Use the beginner form when a condition needs the full
precision of an arbitrary Python expression.
Logical conditions use normal Python precedence (and before or):
if ready and score > 2 then show Go
만약 준비 그리고 점수가 2보다 크면 성공 말해줘
if ready or waiting then show Please wait
run it →Parentheses may surround a whole NME condition in an if or while header,
for example if (ready and score > 2). Keep the header colon-free so NME owns
the line; a valid Python call such as when(ready and score > 2) remains
Python byte-for-byte. Korean sentence endings can stay inside the same wrapper,
as in 만약 (점수가 2보다 작으면). A comparison ending may also precede a
logical connector inside the wrapper, as in 만약 (점수가 2보다 크면 그리고 준비). The same placement works for a Korean while ending, as in
동안 (횟수가 2보다 작을 동안 그리고 준비). The connector spellings can be
mixed too, as in 만약 (점수가 2보다 크면 and 준비).
Korean NME words can also be valid Python identifiers. For example,
만약 (준비) is a valid Python call shape when 만약 is bound, so it stays
byte-identical Python. To make the line an NME block instead, use a spoken
condition ending such as 만약 준비라면, or include an NME connector such as
만약 ((준비 그리고 참)).
Random without code punctuation
set die to random number from 1 to 6
show die
set color to pick from red or green or blue
show color
run it →These forms use Python's bundled random module directly, so a separate
module line is unnecessary.
A chance in percent
30% chance show You win
30% chance
show You win
score add 1
end
luck is a 30% chance
if luck then show Lucky
run it →30% means 300 times in a thousand, and the Python says exactly that:
if __import__("random").randrange(1000) < 300:. Counting in thousandths
keeps every chance a whole number, so nothing is ever decided by comparing two
floating-point numbers that are nearly equal.
A percentage may name one decimal place (30.5%) and nothing finer. 30.25%
is refused with E0227 rather than rounded, because a program must never
quietly mean something its writer did not write. Anything outside 0% to
100% is E0228; 100% always happens and 0% never does.
The same phrase can be written with a 30% chance, a 30% chance,
30 percent chance, or 30% of the time; Korean also takes 30%의 확률로
and 확률 30%로. A percentage on its own is never a chance, so I am 100% sure and 전체의 30%가 왔습니다 stay the ordinary lines they are.
A story block
story:
The door opened slowly.
Nobody was there.
A light came on.
end
run it →Inside a story block every line is text, so a page of prose needs no output
word on every line. Nothing in there is a command: wait 3 seconds prints
those words, and so does if ready. The rule has no exceptions, because a line
of a story that quietly became a statement would be the worst mistake this
compiler could make.
A blank line prints an empty line. Names saved earlier are still put into the
text, exactly as they are in show Hello name!. slow story: tells every line
one character at a time, very slow story: more slowly still, and slow story every 0.2 seconds: at whatever pace you name. The block closes at end / 끝
or, when you opened it by indenting, where the indentation ends.
story: is the first NME form written with a colon. That is deliberate: a bare
story: is a syntax error in Python, so claiming it disturbs the
Python-wins rule not at all, and the colon is the shape Python itself uses to
open a block. It also keeps the form well away from ordinary sentences —
story time and tell me a story carry no colon and stay sentences.
A named job
A named job gives a piece of program a name, so it can be run later by that name. Python calls it a function.
to greet:
show Hello
show Nice to meet you
end
do greet
run it →인사하기라는 일:
안녕하세요 말해줘
반가워요 말해줘
끝
인사하기 해줘
run it →to, do, 일, 하기 and 해줘 are among the most ordinary words either
language has, so a job is recognized by structure and never by a word. The
header needs the opening to — or, in Korean, 라는 on the name and 일 or
작업 after it — and a closing : and a block underneath. to be honest
and 할 일이 많습니다 have none of it.
Without a block there is no job. A heading such as To do: or
오늘의 할 일: prints as the line it is, and there is no one-line form, so a
colon in the middle of a sentence can never open one either.
The line that runs a job is gated on something stronger still: the name has
to be one this program already made a job. A Python def that takes no
arguments counts, so the three levels mix freely.
A name saved inside a job stays inside it, and an ordinary Python return
written in there is accepted, because what the job becomes is a real def.
A job may be given one thing. The header names it in front of the job name, and the line that runs the job hands it over the same way:
to greet someone:
show Hello someone!
end
do greet with Mina
run it →이름에게 인사하기라는 일:
안녕하세요 이름! 말해줘
끝
민수에게 인사하기 해줘
run it →How many things a job takes is remembered with its name, so running it the
other way round is refused with E0235 rather than left to become a Python
TypeError at run time on a line that looks right. In English the thing it is
given only has to be a plain name — someone and something are exactly what
a beginner calls it, and the job name in front already carries the check that
keeps a heading from becoming a function.
Sentence grammar has no job that takes two things and no job that hands
something back yet. Write a Python def when you need either — advanced NME
is ordinary Python and passes through untouched.
Typo and connector recovery
NME action words, logical connectors, and condition connectors accept their documented variants and recover one insertion,
deletion, substitution, or adjacent transposition after Python rejects the
line. A common two-keystroke pattern—one extra/missing character combined
with an adjacent swap—is also accepted when it has one clear action. Examples
include 물어바 → 물어봐, 말헤 → 말해, repaet → repeat, and
shwoe → show, thne → then in if score is greater than 5 thne ...,
and 그리거 → 그리고, and 만악에 → 만약에.
Recovery applies only to these action/connector tokens, never to Python expressions, strings, or comments. If a repair is not unique or the sentence has no clear action, NME reports the exact span and a concrete hint instead of silently guessing. This bounded rule is intentional: no compiler can safely infer every possible typo or every human sentence.
Beginner level
Beginner syntax is compact and exact. It accepts every Python expression and is useful when sentence interpretation would be ambiguous. Every documented beginner action has a Korean spelling, and both languages may be mixed.
The <...> parts below are placeholders that stand for real values — copy a
line and replace them, rather than running the template itself:
say <Python expression>
말해 <Python 표현식>
ask <name>
ask <name>, <Python prompt expression>
물어봐 <이름>
물어봐 <이름>, <Python 질문 표현식>
save <name> to <value>
저장 <이름> <값>
설정 <이름> <값>
<count> times:
<횟수>번:
when <condition>:
만약 <조건>:
while <condition>
동안 <조건>
break
멈춰
else if <condition>
아니면 만약에 <조건>
아니면만약에 <조건>
else
아니면
end
끝
use random
랜덤 사용
use zero_knowledge
영지식 사용
Blocks may contain one inline statement after : or several indented lines:
3 times: say "Hi"
3번:
말해 "안녕"
print("advanced Python is fine")
run it →Exact lowering:
| NME | Python |
|---|---|
say value / 말해 값 | print(value) |
ask name / 물어봐 이름 | name = input() |
ask name, prompt | name = input(prompt) |
save name to value / 저장 이름 값 | name = value |
count times: / 횟수번: | for _ in range(count): |
when condition: / 만약 조건: | if (condition): |
while condition / 동안 조건 ... end / 끝 | while (condition): |
break / 멈춰 | break |
else if condition / 아니면 만약에 조건 / 아니면만약에 조건 | elif (condition): |
else / 아니면 | else: |
Expressions are opaque Python spans. NME validates and copies them; it never reformats or reimplements Python expressions.
Advanced level
Advanced NME is Python syntax. Assignments, functions, classes, imports, exceptions, async code, pattern matching, installed Python packages, and all other valid Python features work unchanged.
from pathlib import Path
def words(path):
return Path(path).read_text(encoding="utf-8").split()
for word in words("notes.txt"):
show word
The last line demonstrates that an advanced Python block may contain sentence NME.
Versioned bundled modules
Seven beginner modules ship with NME: random (dice and picks), file
(reading, writing, and JSON), zero_knowledge / 영지식 (a Schnorr
proof-of-knowledge reference implementation), list / 목록, text / 글자,
math / 수학, and date / 날짜. Everything is bundled at 0.0.1 except
zero knowledge, which is at 0.0.2. One use line per module is enough;
importing the same module twice is a collision error:
use random
use file
use zero_knowledge
use list
use text
use math
use date
run it →list, text, math, date and their Korean names are words people write in
ordinary sentences, so NME only reads one as a module when it stands directly
beside the use / 사용 word and no other word is left over on the line.
get the list of names, What is the date today? and
장 볼 목록을 사용해 보세요 are sentences, and they print.
use random latest, use latest random, and use random version "0.0.1" are
equivalents, and so are the Korean spellings 랜덤 사용, 랜덤 사용 최신,
최신 랜덤 사용, and 랜덤 사용 버전 "0.0.1". The file module accepts the
same forms with file / 파일: 파일 사용, 파일 사용 최신, 파일 사용 버전 "0.0.1". The zero-knowledge adapter uses zero_knowledge / 영지식
with the same forms, including 영지식 사용 최신. Strict punctuation-free
English sentence source may use the alias use zeroknowledge latest.
latest / 최신 selects the newest adapter bundled with the installed NME
compiler. It is local and deterministic, not an uncontrolled network update.
Clear one-edit misspellings such as use random lates are recovered. An
unavailable exact version produces an error showing the installed version.
Every spelling exposes both vocabularies:
| English | Korean | Python meaning |
|---|---|---|
random_number(a, b) | 랜덤정수(a, b) | random.randint(a, b) |
random_pick(values) | 랜덤선택(values) | random.choice(values) |
shuffle(values) | 섞기(values) | random.shuffle(values) |
random_version | 랜덤버전 | adapter version string |
| English | Korean | Python meaning |
|---|---|---|
file_read(path) | 파일읽기(path) | pathlib.Path(path).read_text() |
file_write(path, text) | 파일쓰기(path, text) | pathlib.Path(path).write_text(text) |
json_load(path) | json읽기(path) | json.loads(pathlib.Path(path).read_text()) |
json_save(path, value) | json저장(path, value) | pathlib.Path(path).write_text(json.dumps(value)) |
file_version | 파일버전 | adapter version string |
| English | Korean | Python meaning |
|---|---|---|
count(values) | 개수(값들) | len(values) |
sort(values) | 정렬(값들) | sorted(values), a new list |
reverse(values) | 뒤집기(값들) | list(reversed(values)) |
remove(values, x) | 빼기(값들, x) | a new list without x in it |
first(values) | 첫번째(값들) | values[0] |
last(values) | 마지막(값들) | values[-1] |
sum(values) | 합계(값들) | sum(values) |
largest(values) | 최대(값들) | max(values) |
smallest(values) | 최소(값들) | min(values) |
list_version | 목록버전 | adapter version string |
sort, reverse and remove hand back a new list and leave the original
alone. The sentence statements sort friends, reverse friends and
remove Mina from friends change the list itself; both exist because both are
things people mean.
| English | Korean | Python meaning |
|---|---|---|
upper(text) | 대문자(글) | str(text).upper() |
lower(text) | 소문자(글) | str(text).lower() |
trim(text) | 공백없애기(글) | str(text).strip() |
split(text, sep) | 나누기(글, 구분자) | str(text).split(sep) |
join(sep, values) | 합치기(구분자, 값들) | str(sep).join(map(str, values)) |
replace(text, a, b) | 바꾸기(글, a, b) | str(text).replace(a, b) |
starts_with(text, a) | 로시작(글, a) | str(text).startswith(a) |
length(text) | 길이(글) | len(text) |
text_version | 글자버전 | adapter version string |
| English | Korean | Python meaning |
|---|---|---|
root(x) | 제곱근(x) | math.sqrt(x) |
round_to(x, places) | 반올림(x, 자리) | round(x, places); places may be left out |
pi | 원주율 | math.pi |
power(x, y) | 거듭제곱(x, y) | pow(x, y); whole numbers stay whole |
absolute(x) | 절댓값(x) | abs(x) |
floor(x) | 내림(x) | math.floor(x) |
ceil(x) | 올림(x) | math.ceil(x) |
math_version | 수학버전 | adapter version string |
| English | Korean | Python meaning |
|---|---|---|
today() | 오늘() | date.today().isoformat(), text such as "2026-08-19" |
now() | 지금() | datetime.now().strftime("%H:%M") |
year() | 올해() | date.today().year |
month() | 이번달() | date.today().month |
day_of_month() | 오늘일자() | date.today().day |
weekday() | 요일() | the weekday's name; see below |
days_after(n) | 며칠뒤(n) | (date.today() + timedelta(days=n)).isoformat() |
date_version | 날짜버전 | adapter version string |
days_after counts forwards, so a negative number counts backwards:
days_after(-1) is yesterday.
weekday and 요일 are the one place in any bundled module where the two
languages hold different values. Every other helper hands back a number, a
list, or the writer's own text, and one value serves both names. A weekday name
is a word, and a word has to be in some language: on a Wednesday weekday()
answers Wednesday and 요일() answers 수요일. The name you write chooses
the language of the answer.
The clock is the machine's own clock, and the clock a browser hands Python is
UTC. In the browser playground today() is therefore today in UTC and
now() is the time in UTC, which is not the wall clock of a reader outside
that zone. Dates come back as ISO text (2026-08-19), which sorts correctly
and reads the same everywhere.
Every one of these is a plain Python builtin or one call into math or
datetime, so a program using them runs unchanged in the browser as well as on
a desktop Python.
All bundled adapters reserve their helper names. If one already exists, NME stops and asks you to rename it instead of silently overwriting your value.
Schnorr zero-knowledge adapter
The zero-knowledge adapter uses a fixed finite-field group: RFC 3526 MODP
Group 15 (3072-bit safe prime), generator 2, its prime-order subgroup
q = (p - 1) / 2, and 256-bit verifier challenges. Secure random values come
from Python's secrets module.
| English helper | Korean helper | Meaning |
|---|---|---|
zk_secret() | 영지식비밀만들기() | create a nonzero secret scalar |
zk_public(secret) | 영지식공개값(비밀값) | create the public value |
zk_nonce() | 영지식일회값만들기() | create a one-time prover nonce |
zk_commitment(nonce) | 영지식약속(일회값) | first Schnorr message |
zk_challenge() | 영지식도전만들기() | fresh 256-bit verifier challenge |
zk_challenge_except(c) | 영지식다른도전(도전값) | fresh challenge different from c |
zk_response(v,a,c) | 영지식응답(일회값,비밀값,도전값) | Schnorr response |
zk_verify(A,V,c,r) | 영지식검증(공개값,약속값,도전값,응답값) | verify the proof transcript |
zk_simulated_response() | 영지식모의응답만들기() | choose a simulator response |
zk_simulated_commitment(A,c,r) | 영지식모의약속(공개값,도전값,응답값) | simulate a transcript for a preselected challenge |
Both Korean and English sentence surfaces can remove function punctuation for the complete proof flow, and each of the thirteen values has a spelling in both languages:
| English sentence form | Korean sentence form |
|---|---|
zero knowledge secret make | 영지식 비밀 만들기 |
secret zero knowledge public make | 비밀로 영지식 공개값 만들기 |
zero knowledge nonce make | 영지식 일회값 만들기 |
nonce zero knowledge commitment make | 일회값으로 영지식 약속 만들기 |
zero knowledge challenge make | 영지식 도전 만들기 |
challenge different zero knowledge challenge make | 도전과 다른 영지식 도전 만들기 |
nonce secret challenge zero knowledge response make | 일회값과 비밀과 도전으로 영지식 응답 만들기 |
public commitment challenge response zero knowledge verify | 공개값과 약속과 도전과 응답으로 영지식 검증 |
zero knowledge simulated response make | 영지식 모의 응답 만들기 |
public challenge response zero knowledge simulated commitment make | 공개값과 도전과 응답으로 영지식 모의 약속 만들기 |
public commitment context zero knowledge challenge make | 공개값과 약속과 문맥으로 영지식 비대화 도전 만들기 |
secret context zero knowledge proof make | 비밀과 문맥으로 영지식 비대화 증명 만들기 |
public proof context zero knowledge verify | 공개값과 증명과 문맥으로 영지식 비대화 검증 |
Until this release the last five English forms did not exist, and an attempt
at one was saved as a sentence: set ok to p c e z zero knowledge verify
stored a string, so the program ran, checked nothing, and said nothing. See examples/needmorecoin-sentence.en.nme for
a strict ASCII-letters/digits/whitespace example and
examples/zk-schnorr-relay.ko.nme for the Korean proof flow. The verifier
validates subgroup membership and scalar/challenge ranges before checking the
Schnorr equation.
A stored transcript cannot answer a different fresh challenge. A transcript for a challenge chosen in advance can be simulated without the secret, which demonstrates the zero-knowledge property. A live relay is different: an attacker that forwards the verifier's challenge to the real prover can forward the real response back. Bind authentication to the intended channel/session when relay resistance matters.
This adapter is a mathematically faithful learning/reference implementation. CPython big integers are not promised to be constant-time or side-channel hardened, so use an audited production cryptography implementation for real credentials, money, or other sensitive systems.
Run nme modules or nme 모듈 to list versions and names. Files are written
next to the program's working folder, so save them in your project folder.
random is not suitable for passwords or other security decisions.
Modules: importing another .nme program
A program can import named values from another .nme file in the same folder.
The explicit name list is the module's interface — only those names cross the
file boundary, so there is no hidden global state:
from "helper.nme" import greet, score
show greet
The module file defines the values with ordinary NME or Python:
# helper.nme
greet = "hello"
score = 0
run it →nme run (and nme check / nme build) finds helper.nme next to the main
program, transpiles it, and makes it importable; module errors surface with
the module's file name. Imports may chain (helper.nme can import another
module), the file name must be a Python identifier (helper.nme, not
my-helper.nme or shapes.ko.nme), and two imported modules must not share a
name; that collision is reported as E9028 with a repair suggestion. nme compile
does not support module imports yet and reports E9029; use nme run, nme check,
or nme build for a program that imports another .nme file. If an imported
file cannot be opened, the CLI reports E9007 and names the module path.
The same import has a sentence spelling in each language, so a program can be
split across files without meeting from … import …:
use greet from "helper.nme"
use greet, score from "helper.nme"
"helper.nme"에서 greet 가져와
"helper.nme"에서 greet, score 불러와
The quoted path ending in .nme is what makes these lines an import and
nothing else, so use random still loads the bundled random module.
Sentence syntax can read and write files without the module line or Python punctuation. The path is always a quoted string:
read "notes.txt" into memo
memo read "notes.txt"
memo에 "notes.txt" 읽어서
memo에 "notes.txt" 읽어서 저장해
run it →write "hello" to "out.txt"
"out.txt" 파일에 "hello"를 저장해
These lower to pathlib.Path(...).read_text() / .write_text(...) lines, so
the generated Python is the same stdlib the file module teaches. Weak
matches such as read the book or write hello stay plain sentence output
instead of becoming file operations.
Running a program with arguments
Words typed after the program name go to the program, exactly like
python program.py ...:
nme run greet Mina
nme r dice 6
nme 실행 todo add "buy milk"
The program reads them from sys.argv: sys.argv[0] is the program path,
sys.argv[1] the first argument. Options such as --python must come
before the file name; everything after it belongs to the program.
Native backend
A restricted, statically typed core subset can compile straight to native
machine code, independent of CPython. nme native run hello compiles to C
with the system C compiler and runs the executable; nme native build hello -o hello keeps the C source and the executable.
The native core covers: boolean, integer, and finite-float values with + - * % arithmetic
(integer modulo; float modulo is rejected); string literals and string
variables with one binary + concatenation, len, and ==/!= string
comparisons; while/if/else/else if over integer, float, and string
comparisons (including <=/>= and the natural-language "or equal"
connectors), over integer and finite-float truthiness (if ready, while turns;
zero is false), and over boolean literals and bindings (if ready, while ready;
False is false); boolean equality/inequality; the beginner times: loop; break;
logical and/or conditions use Python precedence and short-circuiting;
names assigned on every possible fall-through path of an if/else block
are available after it, and a branch that returns early or breaks its
enclosing loop does not need to assign them, including a terminating path
that contains a nested conditional; functions over integer scalar
parameters with a required top-level
integer return (recursion works); say/show/말해 of
integers, floats, booleans, and strings. Boolean arithmetic, value changes,
boolean function arguments/returns, ordinary Python for loops, Python
inline bodies, and inline value changes remain outside the native core.
Sentence repeats and beginner times:/번: loops may use one-line NME
output bodies, and one-line NME say/show/말해 or break bodies after
then/그러면 are supported for these control statements and branch chains.
A one-line break must be inside a native loop; otherwise it is rejected with
E0102.
Sentence repeats also accept sentence one-line break here bodies, such as
repeat 3 times and break here.
Float arithmetic that would produce a
non-finite result stops with a bilingual runtime error. Everything else — input, modules, files,
classes, packages — is rejected with a clear diagnostic and still runs on
CPython with nme run. Identifiers that collide with C keywords are rejected,
never renamed. See the native core reference for the
accepted surface and the native-backend memo for the
design and honest measured benchmark.
Python conversion
nme convert safely converts Python into a selected level and language:
nme convert app.py --level sentence --language ko -o app.nme
It rewrites single-value print, input assignments, int(input(...)),
for _ in range(...), if, and simple assignments when a
semantics-preserving equivalent exists. Ordinary import random remains
advanced Python so an existing variable named random can never be silently
overwritten. Other lines remain advanced Python.
See the conversion guide.
Source preservation and diagnostics
- Strings and comments are protected by Python tokenization.
- Valid Python is byte-identical.
- Indentation, blank lines, comments, line endings, and physical line counts are preserved.
- NME diagnostics include a plain message, exact caret span, and repair hint.
- Every diagnostic carries a stable error code such as
E0102, printed next to the message aserror[E0102]:. Read the long Korean explanation withnme ko <CODE>(English:nme en <CODE>);nme koalone lists every code. Compiler codes run fromE0001; command-line errors (missing file, unknown command, Python startup) useE9xxxand are explained the same way. - A top-level or inline
returnoutside a Pythondeffunction getsE0106with a bilingual hint; one-line class suites do not inherit an outer function, and valid returns inside functions remain Python. - A top-level or inline Python
continueoutside a loop getsE0107with a bilingual hint; one-line function/class suites do not inherit an outer loop, while validcontinuestatements inside loops remain Python. - A Python
breakoutside a loop getsE0102; one-line function/class suites do not inherit an outer loop, while validbreakstatements inside loops remain Python. The check also covers controls after an earlier semicolon- separated simple statement in the same one-line suite. - A top-level or inline Python
yieldoutside a function getsE0108, andawaitoutside anasync deffunction getsE0109; valid generator and asynchronous function bodies remain Python. yield frominside anasync deffunction getsE0110; useasync forthere, while ordinary generator functions may keepyield fromunchanged.- Python
async forandasync withoutside anasync deffunction getE0111andE0112; valid asynchronous function bodies remain unchanged. - Python
nonlocalwithout an enclosing function getsE0113, including in a one-line function or class suite. A nested function or class under an outer function remains unchanged; CPython separately checks whether the requested name is bound in that outer function. - Python
from ... import *inside a function or class getsE0114, including one-line suites and a star import after an earlier semicolon-separated statement; import the names explicitly there. Module-level star imports, including ones under a module-level conditional, remain unchanged. - Python does not allow
break,continue, orreturninside anexcept*block; NME reportsE0115, including when the control follows an earlier semicolon-separated statement in the handler. Nested function bodies and control flow after the handler suite remain unchanged. - Python does not allow
yieldinside a list, set, dictionary, or generator comprehension; NME reportsE0116. A plainyieldexpression and a generator lambda remain unchanged when Python permits them. - An
async forinside a list, set, dictionary, or generator comprehension outside anasync deffunction getsE0117. Move the comprehension into an async function; valid async comprehensions remain unchanged. - An async generator cannot return a value; NME reports
E0118even when the return appears before the firstyield. One-line Python suites such asasync def stream(): yield 1; return 2use the same function context as a normally indented body, while a barereturnand returns in nested functions remain valid. - A
globalornonlocaldeclaration after an earlier use or assignment in the same scope getsE0119orE0120, including in one-line suites; parameters and annotated targets cannot use either declaration. Put the declaration first. Valid module, nested-function, and comprehension scopes remain unchanged. Names used in annotations count as uses; f-string validation remains CPython's responsibility. - Generator lambdas remain valid advanced Python: a
yieldinsidelambda: ...is checked against the lambda's own function context. - An inline body must contain one statement; an inline
else/elifwithout an open condition getsE0103. Put branch lines in the same explicit condition block before itsend. - Independent problems are collected when possible.
- Korean-led CLI commands receive Korean-first explanations and recovery examples
such as
nme 실행,nme 컴파일, andnme 설치; English command invocations remain English-only.
Current limits
- Sentence interpolation recognizes names introduced by simple assignments, function parameters, simple Python loop targets, NME input, and sentence assignments. Use beginner expressions for unusual dynamic names or ambiguous literal words.
- Sentence comparison vocabulary is intentionally small; arbitrary expressions
and
and/orlogic can use the explicit block form or advanced Python. - The bundled
random,file, andzero_knowledgemodules have easy module syntax in this beta; other Python libraries are used with ordinaryimport. - The zero-knowledge adapter is a learning/reference implementation, not a side-channel-hardened production cryptography library.
checkandbuildask the selected CPython to compile the lowered output; they do not run it. Runtime errors still belong to Python.run,build, andcheckrequire CPython. Optionalcompilerequires Python, Nuitka, and a platform C compiler.- Native compilation does not guarantee that every program is faster or smaller; benchmark the artifact that matters.