OpenScriptv0.5.0Documentation
GitHub

OS1xxx Syntax errors

Every OS1 code, raised when the text of a script cannot be read as a program, from characters the language does not use to indentation, brackets and statements written in the wrong shape.

On this page
  1. What well-formed code looks like
  2. Characters and literals
  3. Indentation and blocks
  4. Brackets and expressions
  5. Statements and names

Syntax errors are the first thing the compiler looks for. They come from the two stages that run before anything else: the lexer (lex), which reads the characters of your file into words, numbers and symbols, and the parser (parse), which reads those into statements and blocks. An OS1xxx code means the text itself is not a program yet, so no name has been looked up, no bar has run and nothing has been drawn. The fix is always local: the line reported, or the line where the bracket or block it names was opened.

Most syntax errors come from three places. Text copied from a web page, a chat message or a document brings invisible spaces and curly quotes with it. Operators typed out of habit, such as && or !, are spelled as words in OpenScript. And indentation is how the language marks a block, so a line one space out of place changes the structure.

What well-formed code looks like

This study follows every layout rule on this page. It marks the high of the NSE opening range, the first fifteen minutes from 09:15 to 09:30, and signals the bar whose close first moves above it. Paste it into a new script to have a known-good reference beside your own.

version 1
study("Opening range breakout", overlay = true)

// A comment runs from // to the end of its line.
var rangeHigh = none
inRange = session.isIn("0915-0930")
rangeStarts = inRange and not orElse(inRange[1], false)

// A block is the lines indented under its header, four spaces per level.
if rangeStarts
    rangeHigh = high
else if inRange
    rangeHigh = max(rangeHigh, high)

// An operator at the end of a line continues the statement on the next.
breakout = not isNone(rangeHigh) and close > rangeHigh and
        close[1] <= rangeHigh[1]

plot(rangeHigh, "Range high", orange)
if breakout
    signal("Breakout")

The rules it follows, and the code you get for breaking each one:

RuleCode when broken
version 1 is the first line that is not blank or a commentOS1021
One statement per line, and no ; anywhereOS1007, OS1018
Indent blocks with spaces, the same amount on every line of a blockOS1002, OS1003
A header such as if has an indented body under itOS1010
A continued line is indented past the line its statement began onOS1028
Comments start with //OS1026, OS1001
Logic is written and, or and notOS1001
One comparison per expressionOS1008
Every ( and [ is closed by its own kind of bracketOS1012, OS1013

Characters and literals

Outside strings and comments, the lexer accepts only plain ASCII letters and digits, the space, the newline and the language's own punctuation. Inside a string or a comment any character is fine, so "Target ₹" and // rupee target both work. When OS1001 refuses a character, its message names the replacement from this table:

You wroteWrite instead
!not
&&and
||or
^ or **pow(a, b)
++a += 1
{ or }indentation, which is how a block is written
A no-break space, an em space or another wide spacea plain space
A tab between two words on a linea plain space
A curly quotation mark, single or doublea straight quote
A letter with an accent in a namethe plain ASCII spelling
#, $ or @ outside a colournothing: delete it, or move the text into a string

OS1001 Unexpected character

Errorlex

Unexpected character char. suggestion

What it means

You typed a character that the language does not use outside a string or a comment. Often you cannot see it: a no-break space or a curly quotation mark arrives with code copied from a web page, a chat message or a document, and it looks exactly like a normal space or quote. The rest are operators typed out of habit, such as !, &&, ||, ^, ** and ++, or braces around a block. The message quotes the character and names the replacement. For an invisible or unusual character it also gives the Unicode number, such as U+00A0, and for spaces, tabs and quotation marks a name such as "a no-break space". A tab at the start of a line is OS1002 instead.

When the character is invisible, delete the text around the reported column and type it again by hand. For a pasted string, retyping its two quotes is usually enough. A # typed to start a comment lands here too: comments start with //.

How to fix it

Delete the character or replace it with the plain ASCII spelling the message names: a plain space for a non-breaking space, a straight quote for a typographic one, not for !, and for &&, or for ||, pow(a, b) for ^.

Before

if !ready
    signal("BUY")

After

if not ready
    signal("BUY")

OS1027 Malformed colour literal

Errorlex

written is not a colour: a colour literal is # and six or eight hexadecimal digits.

What it means

A # followed by hexadecimal digits is a colour, and it needs exactly six digits, as in #ff8800, or eight, where the last two set the transparency, as in #ff880080. The short forms #fff and #ff88 are not accepted, and neither is a character outside 0 to 9 and a to f (capitals A to F are fine). Because the colour is dropped from the line, the console usually shows OS1022 beside this error; correcting the colour clears both. If hex digits are not what you want, a named colour such as orange or rgb() says the same thing.

This is the case of OS1001 for colours. It has its own code because deleting the #, the advice OS1001 gives, would throw away a colour you nearly had right.

How to fix it

Give it six hexadecimal digits, or eight where the last two are the alpha byte. A named colour or rgb(r, g, b) says the same thing without the digits.

Before

plot(close, "Close", #ff88)

After

plot(close, "Close", #ff8800)

OS1029 A name written against a number

Errorlex

written is neither a number nor a name: the number literal ends at number, and a name cannot begin with a digit.

What it means

A name cannot start with a digit, and a number cannot have letters attached to it. The usual causes are a variable called something like 2fast, a unit typed after a quantity (10k, 5m), a binary or octal literal (0b1011, 0o17), and an underscore at the end of a number (1_000_). Numbers are written in decimal, such as 1_000_000 or 2.5e-4, or in hexadecimal with 0x, and an underscore may only sit between two digits.

Rename the variable so it starts with a letter (fast2), and write quantities in full: 10000, not 10k. When you meant a number followed by a name, put an operator between them.

How to fix it

Write the value in a form the language has: a decimal literal, or 0x and hexadecimal digits. There is no binary form and no octal form, and an underscore separates digit groups only where a digit follows it. Where a number and a name were meant as two things, put an operator between them.

Before

mask = 0b1011

After

mask = 0x0b

OS1004 Unterminated string literal

Errorlex

This string literal opens with quote and the line ends before a matching quote.

What it means

A string opens and closes on the same line, with the same kind of quote: "BUY" or 'BUY'. This error is reported at the opening quote when the line ends before a matching one, which almost always means the closing quote is missing. The unclosed string also swallows the ) of the call it sits in, so OS1012 usually appears beside it and goes away when the quote is added.

A string cannot span lines. To build a long message, close each piece and join them with +, ending the line with the + so the statement continues.

How to fix it

Close the string with a matching quote before the end of the line, and join text across lines with + and a continuation.

Before

signal("BUY)

After

signal("BUY")

OS1005 Unknown escape sequence

Errorlex

sequence is not an escape sequence.

What it means

Inside a string, a backslash starts an escape sequence: \n for a new line, \t for a tab, \r, \0, \\ for a backslash, \" and \' for quotes, and \u followed by exactly four hexadecimal digits for any character, such as \u20b9 for the rupee sign. A backslash followed by anything else is refused rather than guessed at. It most often comes from a file path or a pattern pasted with single backslashes: write each backslash as \\.

How to fix it

Double the backslash to write one literally, or use one of the escapes the language defines.

Before

path = "C:\data\bars"

After

path = "C:\\data\\bars"

OS1026 Block comment

Errorlex

marker does not open or close a comment. A comment is written // and runs to the end of its line.

What it means

OpenScript has line comments only: // starts one and it runs to the end of the line. /* and */ are not comment markers, so the compiler reports them where they sit instead of letting an unclosed comment hide the rest of the file. To comment out several lines, put // at the start of each one.

How to fix it

Write // instead, and give every line of a commented region its own //, which every editor does with one keystroke.

Before

lookback = 14 /* bars */

After

lookback = 14 // bars

OS1007 Semicolon

Errorlex

; is not part of the language.

What it means

A statement ends at the end of its line, so there is nothing for a semicolon to do, and a semicolon at the end of a line is refused as well as one between two statements. Delete it, and give each statement a line of its own.

How to fix it

Delete the; and put the second statement on its own line.

Before

fast = ema(close, 9); slow = ema(close, 21)

After

fast = ema(close, 9)
slow = ema(close, 21)

Indentation and blocks

A block is the lines indented under a header: if, else, for, while, switch, case, default, or a function whose body starts on the next line. The block ends at the first line indented as far as its header, or less. Indent with spaces, four per level by convention. Blank lines and lines that hold only a comment never affect a block, so they may sit at any indentation.

OS1002 Tab in indentation

Errorlex

This line is indented with a tab.

What it means

The line is indented with a tab. A tab is drawn at a different width in every editor, so a block marked with tabs could mean one thing on your screen and another on someone else's, and the language accepts spaces only. In the /trading editor the Tab key moves the focus out of the editor rather than typing anything, so a tab almost always arrives in pasted code. Replace each leading tab with four spaces.

How to fix it

Replace the leading tabs with spaces. Four spaces per level is the convention and the formatter's output.

Before

if close > open
	signal("UP")

After

if close > open
    signal("UP")

OS1003 Indentation does not match this block

Errorlex

This line is indented found spaces; the block opened at line line is indented expected.

What it means

Every line of one block must start at exactly the same column, and a single space more or less counts. The message says how many spaces this line has, how many its block has, and which line opened the block. Line it up with the lines above it to keep it in the block, or with the header to end the block there.

A continued statement, one that carries on from the line above because of an open bracket or a trailing operator, follows a different rule: see OS1028.

How to fix it

Indent this line to expected spaces to keep it in the block, or to line's own indentation to end the block here.

Before

if trending
    body = close - open
     wick = high - low

After

if trending
    body = close - open
    wick = high - low

OS1028 A continuation line is not indented past its statement

Errorlex

A continuation line must be indented more deeply than the line its statement began on; line line is indented statement and this line is indented found.

What it means

A statement continues onto the next line when a bracket is still open, when the line ends with an operator, a comma, ?, : or =, or when it ends with a backslash. The continued line must be indented further than the line the statement began on, so that nobody reading the file can mistake it for a new statement. Indent it; any amount deeper than the first line works, and lining it up under the opening bracket reads well.

This is the case of OS1003 for continued lines. It has its own code because a continuation opens no block, so the block rule's message would describe a block that is not there.

How to fix it

Indent this line further than the statement spaces on line line. Four more is the convention and the formatter's output.

Before

total = ema(close, 9) +
ema(close, 21)

After

total = ema(close, 9) +
        ema(close, 21)

OS1010 Block header with no body

Errorparse

header opens a block, and the next line is not indented more deeply.

What it means

A header line promises an indented body, and the next line is not indented more deeply. This is nearly always a body that lost its indentation when it was pasted. Indent the body under the header.

if, else, the loops, case and default have no one-line form, so even a body of one statement goes on its own indented line. A function can be written on one line by putting its body after =>: fn barRange() => high - low. Blank and comment lines do not count as a body.

How to fix it

Indent the body under the header, or delete the header line if the body is genuinely empty.

Before

if crossUp(fast, slow)
signal("BUY")

After

if crossUp(fast, slow)
    signal("BUY")

OS1016 else does not follow an if

Errorparse

This else is indented found spaces and the nearest if is indented expected.

What it means

An else belongs to the if at exactly its own indentation. At any other indentation there is no if for it to pair with, and the compiler does not guess which one you meant. Line the else up with its if. An else if is written as two words on one line and is not indented further than the if.

An else with no if above it at all, such as one written after a for block, is reported the same way. When the else is indented by a stray space or two, OS1003 usually appears on the same line; lining it up clears both.

How to fix it

Line the else up with its if, at expected spaces.

Before

if trending
    signal("BUY")
  else
    signal("WAIT")

After

if trending
    signal("BUY")
else
    signal("WAIT")

Brackets and expressions

OS1012 Bracket is never closed

Errorparse

The bracket opened at line line is never closed.

What it means

An open ( or [ carries the statement onto the following lines, so when its closer is missing the compiler reads everything after it as part of one long statement. The error is reported at the opening bracket, which is where to look. It usually brings a crowd of other errors from the lines below, such as a continuation that is not indented or a missing comma; add the closer and they go with it. Reading an error shows one missing bracket producing six diagnostics.

How to fix it

Add the matching closer at the end of the argument list on line line.

Before

plot(ema(close, 9), "EMA", aqua

After

plot(ema(close, 9), "EMA", aqua)

OS1013 Mismatched closing bracket

Errorparse

Found found where expected was expected, closing the opener opened at line line.

What it means

A call closes with ), and a history index or an array closes with ]. This error means a bracket was closed with the other kind, such as sum(values] or close[1). The message names the bracket it found, the one it expected and the line the opener is on. Change the closer to match its opener.

How to fix it

Change found to expected, which is what closes the opener opened at line line.

Before

total = sum(closes]

After

total = sum(closes)

OS1014 Missing comma between arguments

Errorparse

Two arguments run together; a comma is missing before token.

What it means

Two values sit side by side inside a call with no comma between them. It usually comes from editing a call: a comma deleted by accident, as in plot(ema(close, 9) "EMA", aqua), or a named argument added without one, as in plot(close, "C" color = aqua). Put the comma back. The compiler reports it rather than guessing where the comma should go.

How to fix it

Put a comma between the two arguments.

Before

plot(ema(close, 9) "EMA", aqua)

After

plot(ema(close, 9), "EMA", aqua)

OS1022 Expression expected

Errorparse

An expression was expected after token.

What it means

A line ends with something that needs more after it (an operator, a comma, = or an opening bracket) and nothing usable follows. It is usually a half-finished edit, or a stray + or , left at the end of a line. Supply the missing value, or delete the trailing symbol.

It also appears beside another error on the same line when that error removed part of the expression, as with a malformed colour (OS1027). Fix the other error first.

How to fix it

Supply the missing operand, or delete the trailing token.

Before

len = input(14, "Length") +

After

len = input(14, "Length")

OS1015 Ternary with no second arm

Errorparse

This ? has no matching :

What it means

The conditional operator, condition ? a : b, always produces a value, so it needs both of its arms. A one-armed version is usually a plot meant to draw on some bars only. Use none for the arm that should draw nothing: plot(ready ? value : none, "Value", aqua). A plot draws a gap wherever its value is none.

How to fix it

Give the ternary both arms, and use none for the arm that should draw nothing.

Before

plot(ready ? value, "Value", aqua)

After

plot(ready ? value : none, "Value", aqua)

OS1008 Chained comparison

Errorparse

A comparison cannot be chained: op1 is already applied before op2.

What it means

30 < r < 70 reads naturally, but it can be read two ways, and a language that places orders does not guess. An expression holds at most one comparison, and that applies to == and != as much as to < and >. Split it with and, writing the middle value twice: 30 < r and r < 70.

The console usually shows OS2003 on the same line as well, because the first comparison produces a bool and the second then compares that bool with a number. Splitting the comparison clears both.

How to fix it

Split it with and, naming the middle value twice: a < b and b < c.

Before

if 30 < r < 70
    zone = "mid"

After

if 30 < r and r < 70
    zone = "mid"

OS1018 More than one statement on a line

Errorparse

Unexpected token after the end of this statement.

What it means

The compiler finished reading a statement and found more on the same line. Either an operator is missing between two values (x = close open), there is one closing bracket too many (ema(close, 9))), or two statements share a line. Add the operator you meant, delete the extra bracket, or move the second statement to its own line.

How to fix it

Put token and what follows it on its own line, or supply the operator that was meant to join them.

Before

fast = ema(close, 9) slow = ema(close, 21)

After

fast = ema(close, 9)
slow = ema(close, 21)

OS1006 Assignment used as a condition

Errorparse

= assigns a value, and a condition needs a comparison.

What it means

= stores a value and == compares two. A condition needs a comparison, so if len = 14 is refused instead of quietly storing 14 and treating the test as true. The same applies to a while condition. Write ==, or, if you did mean to store a value, do it on its own line above the if.

How to fix it

Write == to compare, or move the assignment to its own line above the if.

Before

if len = 14
    signal("DEFAULT")

After

if len == 14
    signal("DEFAULT")

Statements and names

OS1009 break or continue outside a loop

Errorparse

word is only valid inside a for or a while body.

What it means

break leaves the innermost for or while loop, and continue skips to its next pass. Outside a loop body there is nothing for either to act on. To leave a function early, use return. To skip some work on some bars, put that work under an if; plots stay at the top level and take none on the bars they should skip.

How to fix it

Move it inside the loop body, or write return to leave a function early.

Before

fn firstAbove(values, mark) =>
    if size(values) == 0
        break
    values[0]

After

fn firstAbove(values, mark) =>
    if size(values) == 0
        return none
    values[0]

OS1011 var with no initial value

Errorparse

var name has no initial value.

What it means

var declares a value that keeps its content from one bar to the next, and its starting value is part of the declaration, so no bar can ever read it empty by accident. Write var total = 0 to start from zero, or var runningHigh = none to start with no value and fill it on a later bar. See Persistence.

How to fix it

Give it a starting value; var name = none is the empty start.

Before

var runningHigh
if high > orElse(runningHigh, high)
    runningHigh = high

After

var runningHigh = none
if isNone(runningHigh) or high > runningHigh
    runningHigh = high

OS1017 case or default in the wrong place

Errorparse

word is only valid inside a switch, and default must be its last arm.

What it means

case and default are the arms of a switch and exist only inside one, indented under it. default catches everything the cases above it did not, so it must be the last arm: a case after it could never run. Move the arms under their switch, with default at the bottom.

How to fix it

Move the arm inside the switch block, and put default after every case.

Before

switch method
    default
        len = 14
    case "fast"
        len = 9

After

switch method
    case "fast"
        len = 9
    default
        len = 14

OS1019 Reserved word used as a name

Errorparse

word is a reserved word and cannot be used as a name.

What it means

Reserved words belong to the language and cannot name a variable, a function or a function parameter. The ones people reach for most often are color, step, type, in and number. A few, such as type, map and import, are reserved for features planned for later versions, so that adding those features cannot break a script written today. The fix suggests a name that keeps your meaning, such as colorValue. The full list is on Keywords.

A named argument label is not a variable, so plot(x, "X", color = aqua) is fine. Writing bool(x) or number(s) to convert a value lands here too, because the conversions are toBool() and toNumber().

How to fix it

Rename it; suggestion keeps the meaning and is not reserved.

Before

type = input("fast", "Mode", options = ["fast", "slow"])

After

mode = input("fast", "Mode", options = ["fast", "slow"])

OS1020 Incomplete for header

Errorparse

A for header needs = start to end or in array; found token.

What it means

A for loop has two forms and no others. A counted loop names a start and an end, for i = 0 to 9, optionally followed by step, and runs with both ends included. A loop over an array names the array, for price in prices. A comma between the bounds, or a header with no to, is this error. See Control flow.

How to fix it

Write for i = 0 to size(values) - 1 for a counted loop, or for v in values to visit elements.

Before

for i = 0, 9
    total += close[i]

After

for i = 0 to 9
    total += close[i]

OS1021 The version declaration is not first

Errorparse

version must be the first line that is not blank and not a comment; line line came before it.

What it means

version 1 must be the first line of the file, above the study() or strategy() declaration. Only blank lines and comments may come before it. The version is read before anything else so that the script is always compiled by the right version of the language. Move the line to the top.

How to fix it

Move the version line to the top of the file, above the study or strategy declaration.

Before

study("EMA cross")
version 1

After

version 1

study("EMA cross")

OS1023 A function declared inside a block

Errorparse

fn name is declared inside a block, and a function is declared at the top level of the file.

What it means

Functions are declared at the top level of the file, never inside an if, a loop, a switch arm or another function. Move the whole fn declaration out to the top level and call it from inside the block. A function may be called on a line above its declaration, so it can sit anywhere at the top level. See User functions.

How to fix it

Move the whole declaration out to the top level of the file, and call name from inside the block.

Before

if trending
    fn smoothed(src) => sma(src, 9)
    plot(smoothed(close), "Smooth", aqua)

After

fn smoothed(src) => sma(src, 9)

smooth = smoothed(close)
plot(trending ? smooth : none, "Smooth", aqua)

OS1024 Assignment to an indexed element

Errorparse

An assignment writes to a name, and this target is an index into name.

What it means

There is no assignment into brackets. On an array, change an element with set(): set(prices, 0, close). On a series such as close, [1] reads a bar the engine has already computed, and a past bar can never be rewritten. If you want a value of your own, assign it to a plain name.

How to fix it

Change an array element with set(name, i, v), or assign to a plain name: the past of a series is computed and never written.

Before

var prices = [0.0]
prices[0] = close

After

var prices = [0.0]
set(prices, 0, close)

OS1025 Assignment to a member

Errorparse

An assignment writes to a name, and this target is the member member of name.

What it means

A dot reads a member of a namespace such as chart, bar or session, and every member is a fact supplied by the library, the instrument or the position. A script cannot write to any of them, and version 1 has no user-defined records whose fields you could set. Assign the value to a plain name of your own: tick = 0.05, not chart.tickSize = 0.05. When the member does not exist either, OS2009 appears beside this error, as it does for the example below: chart has a tickSize member, not tickStep.

Related. Reading an error, Script structure, Keywords, Operators, Control flow, OS2xxx Names and types

How to fix it

Assign to a plain name. Version 1 has no member assignment: a dot reads a member, and the members a script can reach are facts and functions the library and the host supply.

Before

chart.tickStep = 0.05
plot(close + chart.tickStep, "Stepped", aqua)

After

tickStep = 0.05
plot(close + tickStep, "Stepped", aqua)