Error: Unmatched OUTDENT


#1

Hi,

I’ve been trying my best to assemble a syntax highlighter and I’ve come across a frustrating error I can’t figure out. This is the error:

[stdin]:20:70: error: unmatched OUTDENT		       
                        'match': '\b(open|high|low|close|hl2|hlc3|ohlc4|volume)\b';
		                                                                   ^  
at C:\Users\Matt\.atom\packages\language-thinkscript\grammars\thinkscript.cson:1:1

This is what I have entered:

      {
        'name': 'keyword.price.constants.thinkscript';
        'match': '\b(open|high|low|close|hl2|hlc3|ohlc4|volume)\b';
      },

Thanks in advance for any assistance proffered :slight_smile:


#2

You don’t need semicolons or commas in CSON.


#3

@DamnedScholar Thanks for the reply. I’ve removed the semicolons and commas. Unfortunately, the same error persists…


#4

Mind posting the whole file?


#5

@DamnedScholar Thanks for the swift reply. Here’s the complete file:

{     'scopeName': 'source.thinkscript'
      'name': 'thinkscript'
      'fileTypes': ( 'ts' )
      'foldingStartMarker': '{'
      'foldingStopMarker': '}'
      'patterns' = (
            {    'name': 'constant.numeric.thinkscript'
            'match': '\\b(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))\\b'
            }
          {
                'name': 'keyword.reserved.words.thinkscript'
                'match': '\\b(above|ago|and|bar|bars|below|between|case|crosses|declare|def|default|do|else|equal|equals|false|fold|from|greater|if|input|is|less|no|not|or|plot|profile|rec|reference|script|switch|than|then|to|true|while|with|within|yes)\\b'
          }
          {
                'name': 'keyword.declarations.thinkscript'
                'match': '\\b(hide_on_daily|hide_on_intraday|lower|on_volume|once_per_bar|real_size|upper|weak_volume_dependency|zerobase)\\b'
          }
          {
            'name': 'keyword.price.constants.thinkscript'
                'match': '\\b(open|high|low|close|hl2|hlc3|ohlc4|volume)\\b'
            }
          {
                'name': 'keyword.functions.thinkscript'
                'match': '\\b(ask|bid|imp_volatility|open_interest|vwap|Delta|Gamma|GetATMOption|GetDaysToExpiration|GetNextExpirationOption|GetNextITMOption|GetNextOTMOption|GetStrike|GetUnderlyingSymbol|IsEuropean|IsOptionable|IsPut|OptionPrice|Rho|Theta|Vega|AccumDist|AccumDist|Average|AvgTrueRange|BodyHeight|EMA2|ExpAvrage|FastKCustom|GetMarketMakerMove|GetMaxValueOffset|GetMinValueOffset|Highest|HighestAll|HighestWeighted|IsAscending|IsDescending|IsDoji|IsLongBlack|IsLongWhite|Lowest|LowestAll|LowestWeighted|Median|MidBodyVal|MoneyFlow|MovingAverage|TrueRange|Ulcer|WildersAverage|WMA|AbsValue|ACos|ASin|ATan|Ceil|Cos|Crosses|Exp|Floor|IsInfinite|IsNaN|Lg|Log|Max|Min|Power|Random|Round|RoundDown|RoundUp|Sign|Sin|Sqr|Sqrt|Sum|Tan|TotalSum|Correlation|Covariance|Inertia|InertiaAll|LinDev|StDev|StDevAll|StErr|StErrAll|CountTradingDays|DaysFromDate|DaysTillDate|GetDay|GetDayOfMonth|GetDayOfWeek|GetLastDay|GetLastMonth|GetLastWeek|GetLastYear|GetMonth|GetWeek|GetYear|GetYYYYMMDD|RegularTradingEnd|RegularTradingStart|SecondsFromTime|SecondsTillTime|GetActualEarnings|GetDividend|GetEstimatedEarnings|GetEventOffset|GetSplitDenominator|GetSplitNumerator|HasConferenceCall|HasEarnings|AddChartBubble|AddCloud|AddLabel|AddVerticalLine|AssignBackgroundColor|AssignNormGradientColor|AssignPriceColor|AssignValueColor|Color|CreateColor|DefineColor|DefineGlobalColor|EnableApproximation|GetColor|GlobalColor|Hide|HideBubble|HidePricePlot|HideTitle|SetChartType|SetDefaultColor|SetHiding|SetLineWeight|SetPaintingStrategy|SetStyle|TakeValueColor|GetHighest|GetHighestValueArea|GetLowest|GetLowestValueArea|GetPointOfControl|MonkeyBars|Show|TimeProfile|VolumeProfile|AddOrder|Alert|AsDollars|AsPercent|AsPrice|Assert|AsText|BarNumber|Between|CompoundValue|Concat|EntryPrice|First|FPL|Fundamental|GetAggregationPeriod|GetInterestRate|GetPriceType|GetSymbol|GetSymbolPart|GetValue|GetYield|HasContractChangeEvent|If|TickSize|TickValue)\\b'
            }
          {
                'name': 'keyword.constants.thinkscript'
            'match': '\\b(AggregationPeriod|Alert|AverageType|ChartType|Color|CrossingDirection|Curve|Double|EarningTime|Events|FundamentalType|MonkeyVolumeShowStyle|NumberFormat|OptionClass|OrderType|PaintingStrategy|PricePerRow|Sound|NoSound|Bell|Ding|Ring|Chime||MIN|TWO_MIN|THREE_MIN|FOUR_MIN|FIVE_MIN|TEN_MIN|FIFTEEN_MIN|TWENTY_MIN|THIRTY_MIN|HOUR|TWO_HOURS|FOUR_HOURS|DAY|TWO_DAYS|THREE_DAYS|FOUR_DAYS|WEEK|MONTH|OPT_EXP|BAR|ONCE|TICK|EXPONENTIAL|HULL|SIMPLE|WEIGHTED|WILDERS|BAR|CANDLE|CANDLE_TREND|HEIKIN_ASHI|EQUIVOLUME|LINE|AREA|BLACK|BLUE|CURRENT|CYAN|DARK_GRAY|DARK_GREEN|DARK_ORANGE|DARK_RED|DOWNTICK|GRAY|GREEN|LIGHT_GRAY|LIGHT_GREEN|LIGHT_ORANGE|LIGHT_RED|LIME|MAGENTA|ORANGE|PINK|PLUM|RED|UPTICK|VIOLET|WHITE|YELLOW|ABOVE|BELOW|ANY|FIRM|LONG_DASH|MEDIUM_DASH|SHORT_DASH|POINTS|E|NaN|NEGATIVE_INFINITY|Pi|POSITIVE_INFINITY|ANY|BEFORE_MARKET|AFTER_MARKET|CONFERENCE_CALL|DIVIDEND|EARNINGS|SPLIT|HIGH|LOW|CLOSE|OPEN|HL2|HLC3|OHLC4|VWAP|VOLUME|OPEN_INTEREST|IMP_VOLATILITY|ALL|LAST|NONE|DOLLAR|THREE_DECIMAL_PLACES|TWO_DECIMAL_PLACES|CALL|PUT|BUY_AUTO|BUY_TO_CLOSE|BUY_TO_OPEN|SELL_AUTO|SELL_TO_CLOSE|SELL_TO_OPEN|ARROW_DOWN|ARROW_UP|BOOLEAN_ARROW_DOWN|BOOLEAN_ARROW_UP|BOOLEAN_POINTS|DASHES|HISTOGRAM|HORIZONTAL|LINE|LINE_VS_POINTS|LINE_VS_SQUARES|LINE_VS_TRIANGLES|POINTS|SQUARED_HISTOGRAM|SQUARES|TRIANGLES|VALUES_ABOVE|VALUES_BELOW|AUTOMATIC|TICKSIZE)\\b'
            }
          {
                'name': 'keyword.operators.thinkscript'
                'match': '\\b(!|%|&|*|+|-|//|/|:|<|=|>|?|[|]|^|&&)\\b'
            }
          {
                'name': 'keyword.separators.thinkscript'
                'match': '\\b(.|(|)|,|;|{|})\\b'
            }
          {
                'name': 'keyword.delimiters.thinkscript'
                'match': '\\b(~|!|@|%|^|&|*|(|)|-|+|=|\|/|{|}|[|]|:|;|"|'|<|>|,|.|?)\\b'
            }
          {
            'name': 'comment.line.number-sign.thinkscript'
              'match': '((#).*$\\n?)|((; ).*$\\n?))'
          }
      )
}

#6

You need to wrap that in backticks if you’re going to post it here. Indentation is very important in CoffeeScript.


#7

@DamnedScholar Thanks again for the swift reply. I’ve edited my prior post to reflect what I’m hoping are the correct indentations. Thanks also for posting the sample grammar file…


#8

The big problem is that the indentation isn’t consistent. When you have name and match not aligned vertically, the CSON interpreter has no idea what to think. I’ve cleaned that up for you, and a few other things. This should work just fine:

scopeName: 'source.thinkscript'
name: 'thinkscript'
fileTypes: [
  'ts'
]
foldingStartMarker: '{'
foldingStopMarker: '}'
patterns: [
  {
    name: 'constant.numeric.thinkscript'
    match: '\\b(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))\\b'
  }
  {
    name: 'keyword.reserved.words.thinkscript'
    match: '\\b(above|ago|and|bar|bars|below|between|case|crosses|declare|def|default|do|else|equal|equals|false|fold|from|greater|if|input|is|less|no|not|or|plot|profile|rec|reference|script|switch|than|then|to|true|while|with|within|yes)\\b'
  }
  {
    name: 'keyword.declarations.thinkscript'
    match: '\\b(hide_on_daily|hide_on_intraday|lower|on_volume|once_per_bar|real_size|upper|weak_volume_dependency|zerobase)\\b'
  }
  {
    name: 'keyword.price.constants.thinkscript'
    match: '\\b(open|high|low|close|hl2|hlc3|ohlc4|volume)\\b'
  }
  {
    name: 'keyword.functions.thinkscript'
    match: '\\b(ask|bid|imp_volatility|open_interest|vwap|Delta|Gamma|GetATMOption|GetDaysToExpiration|GetNextExpirationOption|GetNextITMOption|GetNextOTMOption|GetStrike|GetUnderlyingSymbol|IsEuropean|IsOptionable|IsPut|OptionPrice|Rho|Theta|Vega|AccumDist|AccumDist|Average|AvgTrueRange|BodyHeight|EMA2|ExpAvrage|FastKCustom|GetMarketMakerMove|GetMaxValueOffset|GetMinValueOffset|Highest|HighestAll|HighestWeighted|IsAscending|IsDescending|IsDoji|IsLongBlack|IsLongWhite|Lowest|LowestAll|LowestWeighted|Median|MidBodyVal|MoneyFlow|MovingAverage|TrueRange|Ulcer|WildersAverage|WMA|AbsValue|ACos|ASin|ATan|Ceil|Cos|Crosses|Exp|Floor|IsInfinite|IsNaN|Lg|Log|Max|Min|Power|Random|Round|RoundDown|RoundUp|Sign|Sin|Sqr|Sqrt|Sum|Tan|TotalSum|Correlation|Covariance|Inertia|InertiaAll|LinDev|StDev|StDevAll|StErr|StErrAll|CountTradingDays|DaysFromDate|DaysTillDate|GetDay|GetDayOfMonth|GetDayOfWeek|GetLastDay|GetLastMonth|GetLastWeek|GetLastYear|GetMonth|GetWeek|GetYear|GetYYYYMMDD|RegularTradingEnd|RegularTradingStart|SecondsFromTime|SecondsTillTime|GetActualEarnings|GetDividend|GetEstimatedEarnings|GetEventOffset|GetSplitDenominator|GetSplitNumerator|HasConferenceCall|HasEarnings|AddChartBubble|AddCloud|AddLabel|AddVerticalLine|AssignBackgroundColor|AssignNormGradientColor|AssignPriceColor|AssignValueColor|Color|CreateColor|DefineColor|DefineGlobalColor|EnableApproximation|GetColor|GlobalColor|Hide|HideBubble|HidePricePlot|HideTitle|SetChartType|SetDefaultColor|SetHiding|SetLineWeight|SetPaintingStrategy|SetStyle|TakeValueColor|GetHighest|GetHighestValueArea|GetLowest|GetLowestValueArea|GetPointOfControl|MonkeyBars|Show|TimeProfile|VolumeProfile|AddOrder|Alert|AsDollars|AsPercent|AsPrice|Assert|AsText|BarNumber|Between|CompoundValue|Concat|EntryPrice|First|FPL|Fundamental|GetAggregationPeriod|GetInterestRate|GetPriceType|GetSymbol|GetSymbolPart|GetValue|GetYield|HasContractChangeEvent|If|TickSize|TickValue)\\b'
  }
  {
    name: 'keyword.constants.thinkscript'
    match: '\\b(AggregationPeriod|Alert|AverageType|ChartType|Color|CrossingDirection|Curve|Double|EarningTime|Events|FundamentalType|MonkeyVolumeShowStyle|NumberFormat|OptionClass|OrderType|PaintingStrategy|PricePerRow|Sound|NoSound|Bell|Ding|Ring|Chime||MIN|TWO_MIN|THREE_MIN|FOUR_MIN|FIVE_MIN|TEN_MIN|FIFTEEN_MIN|TWENTY_MIN|THIRTY_MIN|HOUR|TWO_HOURS|FOUR_HOURS|DAY|TWO_DAYS|THREE_DAYS|FOUR_DAYS|WEEK|MONTH|OPT_EXP|BAR|ONCE|TICK|EXPONENTIAL|HULL|SIMPLE|WEIGHTED|WILDERS|BAR|CANDLE|CANDLE_TREND|HEIKIN_ASHI|EQUIVOLUME|LINE|AREA|BLACK|BLUE|CURRENT|CYAN|DARK_GRAY|DARK_GREEN|DARK_ORANGE|DARK_RED|DOWNTICK|GRAY|GREEN|LIGHT_GRAY|LIGHT_GREEN|LIGHT_ORANGE|LIGHT_RED|LIME|MAGENTA|ORANGE|PINK|PLUM|RED|UPTICK|VIOLET|WHITE|YELLOW|ABOVE|BELOW|ANY|FIRM|LONG_DASH|MEDIUM_DASH|SHORT_DASH|POINTS|E|NaN|NEGATIVE_INFINITY|Pi|POSITIVE_INFINITY|ANY|BEFORE_MARKET|AFTER_MARKET|CONFERENCE_CALL|DIVIDEND|EARNINGS|SPLIT|HIGH|LOW|CLOSE|OPEN|HL2|HLC3|OHLC4|VWAP|VOLUME|OPEN_INTEREST|IMP_VOLATILITY|ALL|LAST|NONE|DOLLAR|THREE_DECIMAL_PLACES|TWO_DECIMAL_PLACES|CALL|PUT|BUY_AUTO|BUY_TO_CLOSE|BUY_TO_OPEN|SELL_AUTO|SELL_TO_CLOSE|SELL_TO_OPEN|ARROW_DOWN|ARROW_UP|BOOLEAN_ARROW_DOWN|BOOLEAN_ARROW_UP|BOOLEAN_POINTS|DASHES|HISTOGRAM|HORIZONTAL|LINE|LINE_VS_POINTS|LINE_VS_SQUARES|LINE_VS_TRIANGLES|POINTS|SQUARED_HISTOGRAM|SQUARES|TRIANGLES|VALUES_ABOVE|VALUES_BELOW|AUTOMATIC|TICKSIZE)\\b'
  }
  {
    name: 'keyword.operators.thinkscript'
    match: '\\b(!|%|&|*|+|-|//|/|:|<|=|>|?|[|]|^|&&)\\b'
  }
  {
    name: 'keyword.separators.thinkscript'
    match: '\\b(.|(|)|,|;|{|})\\b'
  }
  {
    name: 'keyword.delimiters.thinkscript'
    match: '\\b(~|!|@|%|^|&|*|(|)|-|+|=|\|/|{|}|[|]|:|;|"|\'|<|>|,|.|?)\\b'
  }
  {
    name: 'comment.line.number-sign.thinkscript'
    match: '((#).*$\\n?)|((; ).*$\\n?))'
  }
]

#9

@DamnedScholar Thanks for your continued assistance. Unfortunately, I’ve run into another bug:

[stdin]:47:40: error: unmatched OUTDENT    
     match: '((#).*$\\n?)|((; ).*$\\n?))'
                                         ^ 
 at C:\Users\Matt\.atom\packages\language-thinkscript\grammars\thinkscript.cson:1:1

#10

They’re not bugs, they’re syntax errors. You actually have one too many closing parentheses in that line. It should be written as '(((#).*$\\n?)|((; ).*$\\n?))'. Also, in looking at the regexes, there are some other mistakes. For instance, (|) does literally nothing. It’s a capture group that’s checking for nothing or nothing. You should escape any instances of (), {}, [], or | that you want to actually be checked for.


#11

@DamnedScholar Thanks for the clarification and additional insights. I sincerely appreciate your time and efforts in this thread.

Since I am a “noob” when it comes to all things Atom and CoffeeScript, having consulted your sample grammar file, is there any additional resource I could follow that will help me properly resolve the outstanding issues with this grammar file?


#12

Just read up on regular expressions. When I’m making a regular expression of any complexity, I always use an online tool to check the expression against any text I’m checking for. It makes it easy to see if anything has been left out.


#13

Thanks for the tip. I actually did use regex101 and another one as well. I’ll look into the Regex Guide and revisit the online tools…